diff options
Diffstat (limited to 'src/network')
39 files changed, 622 insertions, 362 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 42c7c80f3b..17897ca869 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -37,7 +37,8 @@ HEADERS += \ access/qnetworkdiskcache.h \ access/qhttpthreaddelegate_p.h \ access/qhttpmultipart.h \ - access/qhttpmultipart_p.h + access/qhttpmultipart_p.h \ + access/qnetworkfile_p.h SOURCES += \ access/qftp.cpp \ @@ -68,7 +69,8 @@ SOURCES += \ access/qabstractnetworkcache.cpp \ access/qnetworkdiskcache.cpp \ access/qhttpthreaddelegate.cpp \ - access/qhttpmultipart.cpp + access/qhttpmultipart.cpp \ + access/qnetworkfile.cpp mac: LIBS_PRIVATE += -framework Security diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 3601c36bc2..24ada3a81f 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -484,8 +484,7 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) } // is this a valid reply? - if (fragment.length() >= 5 && !fragment.startsWith("HTTP/")) - { + if (fragment.length() == 5 && !fragment.startsWith("HTTP/")) { fragment.clear(); return -1; } @@ -739,6 +738,8 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuff #ifndef QT_NO_COMPRESS int QHttpNetworkReplyPrivate::initializeInflateStream() { + Q_ASSERT(inflateStrm); + inflateStrm->zalloc = Z_NULL; inflateStrm->zfree = Z_NULL; inflateStrm->opaque = Z_NULL; diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index d2b1a8a912..ed586c1de5 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1523,27 +1523,35 @@ void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) manager->d_func()->objectCache.clear(); manager->d_func()->authenticationManager->clearCache(); - if (manager->d_func()->httpThread) { - manager->d_func()->httpThread->quit(); - manager->d_func()->httpThread->wait(5000); - if (manager->d_func()->httpThread->isFinished()) - delete manager->d_func()->httpThread; - else - QObject::connect(manager->d_func()->httpThread, SIGNAL(finished()), manager->d_func()->httpThread, SLOT(deleteLater())); - manager->d_func()->httpThread = 0; - } + manager->d_func()->destroyThread(); } QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate() { - if (httpThread) { - httpThread->quit(); - httpThread->wait(5000); - if (httpThread->isFinished()) - delete httpThread; + destroyThread(); +} + +QThread * QNetworkAccessManagerPrivate::createThread() +{ + if (!thread) { + thread = new QThread; + thread->setObjectName(QStringLiteral("QNetworkAccessManager thread")); + thread->start(); + } + Q_ASSERT(thread); + return thread; +} + +void QNetworkAccessManagerPrivate::destroyThread() +{ + if (thread) { + thread->quit(); + thread->wait(5000); + if (thread->isFinished()) + delete thread; else - QObject::connect(httpThread, SIGNAL(finished()), httpThread, SLOT(deleteLater())); - httpThread = 0; + QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + thread = 0; } } diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 4efa30df49..9d02fd7c34 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -172,6 +172,7 @@ private: friend class QNetworkReplyImplPrivate; friend class QNetworkReplyHttpImpl; friend class QNetworkReplyHttpImplPrivate; + friend class QNetworkReplyFileImpl; Q_DECLARE_PRIVATE(QNetworkAccessManager) Q_PRIVATE_SLOT(d_func(), void _q_replyFinished()) diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index 413de2a4fe..48270f0c17 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -74,7 +74,7 @@ class QNetworkAccessManagerPrivate: public QObjectPrivate public: QNetworkAccessManagerPrivate() : networkCache(0), cookieJar(0), - httpThread(0), + thread(0), #ifndef QT_NO_NETWORKPROXY proxyFactory(0), #endif @@ -107,6 +107,9 @@ public: } ~QNetworkAccessManagerPrivate(); + QThread * createThread(); + void destroyThread(); + void _q_replyFinished(); void _q_replyEncrypted(); void _q_replySslErrors(const QList<QSslError> &errors); @@ -158,7 +161,7 @@ public: QNetworkCookieJar *cookieJar; - QThread *httpThread; + QThread *thread; #ifndef QT_NO_NETWORKPROXY diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index 99e67cb463..68c962636e 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -421,7 +421,7 @@ QIODevice *QNetworkDiskCache::data(const QUrl &url) // ### verify that QFile uses the fd size and not the file name qint64 size = file->size() - file->pos(); const uchar *p = 0; -#if !defined(Q_OS_WINCE) && !defined(Q_OS_INTEGRITY) +#if !defined(Q_OS_INTEGRITY) p = file->map(file->pos(), size); #endif if (p) { diff --git a/src/network/kernel/qnetworkfunctions_wince.h b/src/network/access/qnetworkfile.cpp index 0e464a47f3..374dd26e2e 100644 --- a/src/network/kernel/qnetworkfunctions_wince.h +++ b/src/network/access/qnetworkfile.cpp @@ -37,60 +37,56 @@ ** ****************************************************************************/ -#ifndef QNETWORKFUNCTIONS_WINCE_H -#define QNETWORKFUNCTIONS_WINCE_H +#include "qnetworkfile_p.h" -#if 0 -#pragma qt_sync_stop_processing -#endif +#include <QtCore/QDebug> +#include <QNetworkReply> +#include <QtCore/QDateTime> +#include <QtCore/QFileInfo> +#include <QtCore/QMetaObject> +#include <QtCore/QCoreApplication> -#ifdef Q_OS_WINCE +QT_BEGIN_NAMESPACE -#include <qt_windows.h> +QNetworkFile::QNetworkFile() + : QFile() +{ +} -QT_BEGIN_NAMESPACE +QNetworkFile::QNetworkFile(const QString &name) + : QFile(name) +{ +} -DECLARE_HANDLE(SC_HANDLE); -typedef enum _SC_ENUM_TYPE { - SC_ENUM_PROCESS_INFO = 0 -} SC_ENUM_TYPE; -#define SC_MANAGER_CONNECT 0x0001 -#define SC_MANAGER_CREATE_SERVICE 0x0002 -#define SC_MANAGER_ENUMERATE_SERVICE 0x0004 -#define SERVICE_ACTIVE 0x00000001 -#define SERVICE_INACTIVE 0x00000002 -#define SERVICE_STATE_ALL (SERVICE_ACTIVE | \ - SERVICE_INACTIVE) -typedef struct _SERVICE_STATUS_PROCESS { - DWORD dwServiceType; - DWORD dwCurrentState; - DWORD dwControlsAccepted; - DWORD dwWin32ExitCode; - DWORD dwServiceSpecificExitCode; - DWORD dwCheckPoint; - DWORD dwWaitHint; - DWORD dwProcessId; - DWORD dwServiceFlags; -} SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS; -typedef struct _ENUM_SERVICE_STATUS_PROCESSA { - LPSTR lpServiceName; - LPSTR lpDisplayName; - SERVICE_STATUS_PROCESS ServiceStatusProcess; -} ENUM_SERVICE_STATUS_PROCESSA, *LPENUM_SERVICE_STATUS_PROCESSA; -typedef struct _ENUM_SERVICE_STATUS_PROCESSW { - LPWSTR lpServiceName; - LPWSTR lpDisplayName; - SERVICE_STATUS_PROCESS ServiceStatusProcess; -} ENUM_SERVICE_STATUS_PROCESSW, *LPENUM_SERVICE_STATUS_PROCESSW; -#ifdef UNICODE -typedef ENUM_SERVICE_STATUS_PROCESSW ENUM_SERVICE_STATUS_PROCESS; -typedef LPENUM_SERVICE_STATUS_PROCESSW LPENUM_SERVICE_STATUS_PROCESS; -#else -typedef ENUM_SERVICE_STATUS_PROCESSA ENUM_SERVICE_STATUS_PROCESS; -typedef LPENUM_SERVICE_STATUS_PROCESSA LPENUM_SERVICE_STATUS_PROCESS; -#endif // UNICODE +void QNetworkFile::open() +{ + bool opened = false; + QFileInfo fi(fileName()); + if (fi.isDir()) { + QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", + "Cannot open %1: Path is a directory").arg(fileName()); + error(QNetworkReply::ContentOperationNotPermittedError, msg); + } else { + headerRead(QNetworkRequest::LastModifiedHeader, QVariant::fromValue(fi.lastModified())); + headerRead(QNetworkRequest::ContentLengthHeader, QVariant::fromValue(fi.size())); + opened = QFile::open(QIODevice::ReadOnly | QIODevice::Unbuffered); + if (!opened) { + QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", + "Error opening %1: %2").arg(fileName(), errorString()); + if (exists()) + error(QNetworkReply::ContentAccessDenied, msg); + else + error(QNetworkReply::ContentNotFoundError, msg); + } + } + finished(opened); +} -QT_END_NAMESPACE +void QNetworkFile::close() +{ + // This override is needed because 'using' keyword cannot be used for slots. And the base + // function is not an invokable/slot function. + QFile::close(); +} -#endif // Q_OS_WINCE -#endif // QNETWORKFUNCTIONS_WINCE_H +QT_END_NAMESPACE diff --git a/src/network/access/qnetworkfile_p.h b/src/network/access/qnetworkfile_p.h new file mode 100644 index 0000000000..7794c0f18a --- /dev/null +++ b/src/network/access/qnetworkfile_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 QNETWORKFILE_H +#define QNETWORKFILE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the Network Access API. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QFile> +#include <qnetworkreply.h> + +QT_BEGIN_NAMESPACE + +class QNetworkFile : public QFile +{ + Q_OBJECT +public: + QNetworkFile(); + QNetworkFile(const QString &name); + using QFile::open; + +public Q_SLOTS: + void open(); + void close() Q_DECL_OVERRIDE; + +Q_SIGNALS: + void finished(bool ok); + void headerRead(QNetworkRequest::KnownHeaders header, const QVariant &value); + void error(QNetworkReply::NetworkError error, const QString &message); +}; + +QT_END_NAMESPACE + +#endif // QNETWORKFILE_H diff --git a/src/network/access/qnetworkreplyfileimpl.cpp b/src/network/access/qnetworkreplyfileimpl.cpp index 36bc4b41df..ef319ebf0d 100644 --- a/src/network/access/qnetworkreplyfileimpl.cpp +++ b/src/network/access/qnetworkreplyfileimpl.cpp @@ -40,31 +40,45 @@ #include "qnetworkreplyfileimpl_p.h" #include "QtCore/qdatetime.h" +#include "qnetworkaccessmanager_p.h" #include <QtCore/QCoreApplication> #include <QtCore/QFileInfo> +#include <QtCore/QThread> +#include "qnetworkfile_p.h" +#include "qnetworkrequest.h" QT_BEGIN_NAMESPACE QNetworkReplyFileImplPrivate::QNetworkReplyFileImplPrivate() - : QNetworkReplyPrivate(), realFileSize(0) + : QNetworkReplyPrivate(), managerPrivate(0), realFile(0) { + qRegisterMetaType<QNetworkRequest::KnownHeaders>(); + qRegisterMetaType<QNetworkReply::NetworkError>(); } QNetworkReplyFileImpl::~QNetworkReplyFileImpl() { + QNetworkReplyFileImplPrivate *d = (QNetworkReplyFileImplPrivate*) d_func(); + if (d->realFile) { + if (d->realFile->thread() == QThread::currentThread()) + delete d->realFile; + else + QMetaObject::invokeMethod(d->realFile, "deleteLater", Qt::QueuedConnection); + } } -QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op) - : QNetworkReply(*new QNetworkReplyFileImplPrivate(), parent) +QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, const QNetworkRequest &req, const QNetworkAccessManager::Operation op) + : QNetworkReply(*new QNetworkReplyFileImplPrivate(), manager) { setRequest(req); setUrl(req.url()); setOperation(op); - setFinished(true); QNetworkReply::open(QIODevice::ReadOnly); QNetworkReplyFileImplPrivate *d = (QNetworkReplyFileImplPrivate*) d_func(); + d->managerPrivate = manager->d_func(); + QUrl url = req.url(); if (url.host() == QLatin1String("localhost")) url.setHost(QString()); @@ -77,7 +91,7 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ setError(QNetworkReply::ProtocolInvalidOperationError, msg); QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProtocolInvalidOperationError)); - QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + fileOpenFinished(false); return; } #endif @@ -85,7 +99,6 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ url.setPath(QLatin1String("/")); setUrl(url); - QString fileName = url.toLocalFile(); if (fileName.isEmpty()) { const QString scheme = url.scheme(); @@ -101,68 +114,85 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ } } - QFileInfo fi(fileName); - if (fi.isDir()) { - QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Cannot open %1: Path is a directory").arg(url.toString()); - setError(QNetworkReply::ContentOperationNotPermittedError, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, - Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentOperationNotPermittedError)); - QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); - return; - } - - d->realFile.setFileName(fileName); - bool opened = d->realFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered); - - // could we open the file? - if (!opened) { - QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Error opening %1: %2") - .arg(d->realFile.fileName(), d->realFile.errorString()); - - if (d->realFile.exists()) { - setError(QNetworkReply::ContentAccessDenied, msg); - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, - Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentAccessDenied)); - } else { - setError(QNetworkReply::ContentNotFoundError, msg); + if (req.attribute(QNetworkRequest::BackgroundRequestAttribute).toBool()) { // Asynchronous open + auto realFile = new QNetworkFile(fileName); + connect(realFile, &QNetworkFile::headerRead, this, &QNetworkReplyFileImpl::setHeader, + Qt::QueuedConnection); + connect(realFile, &QNetworkFile::error, this, &QNetworkReplyFileImpl::setError, + Qt::QueuedConnection); + connect(realFile, SIGNAL(finished(bool)), SLOT(fileOpenFinished(bool)), + Qt::QueuedConnection); + + realFile->moveToThread(d->managerPrivate->createThread()); + QMetaObject::invokeMethod(realFile, "open", Qt::QueuedConnection); + + d->realFile = realFile; + } else { // Synch open + setFinished(true); + + QFileInfo fi(fileName); + if (fi.isDir()) { + QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Cannot open %1: Path is a directory").arg(url.toString()); + setError(QNetworkReply::ContentOperationNotPermittedError, msg); QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, - Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentNotFoundError)); + Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentOperationNotPermittedError)); + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + return; + } + d->realFile = new QFile(fileName, this); + bool opened = d->realFile->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + // could we open the file? + if (!opened) { + QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Error opening %1: %2") + .arg(d->realFile->fileName(), d->realFile->errorString()); + + if (fi.exists()) { + setError(QNetworkReply::ContentAccessDenied, msg); + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentAccessDenied)); + } else { + setError(QNetworkReply::ContentNotFoundError, msg); + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentNotFoundError)); + } + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + return; } + setHeader(QNetworkRequest::LastModifiedHeader, fi.lastModified()); + setHeader(QNetworkRequest::ContentLengthHeader, fi.size()); + + QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "downloadProgress", Qt::QueuedConnection, + Q_ARG(qint64, fi.size()), Q_ARG(qint64, fi.size())); + QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); - return; } - - setHeader(QNetworkRequest::LastModifiedHeader, fi.lastModified()); - d->realFileSize = fi.size(); - setHeader(QNetworkRequest::ContentLengthHeader, d->realFileSize); - - QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection); - QMetaObject::invokeMethod(this, "downloadProgress", Qt::QueuedConnection, - Q_ARG(qint64, d->realFileSize), Q_ARG(qint64, d->realFileSize)); - QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); - QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } void QNetworkReplyFileImpl::close() { Q_D(QNetworkReplyFileImpl); QNetworkReply::close(); - d->realFile.close(); + if (d->realFile) { + if (d->realFile->thread() == thread()) + d->realFile->close(); + else + QMetaObject::invokeMethod(d->realFile, "close", Qt::QueuedConnection); + } } void QNetworkReplyFileImpl::abort() { - Q_D(QNetworkReplyFileImpl); - QNetworkReply::close(); - d->realFile.close(); + close(); } qint64 QNetworkReplyFileImpl::bytesAvailable() const { Q_D(const QNetworkReplyFileImpl); - if (!d->realFile.isOpen()) + if (!d->isFinished || !d->realFile || !d->realFile->isOpen()) return QNetworkReply::bytesAvailable(); - return QNetworkReply::bytesAvailable() + d->realFile.bytesAvailable(); + return QNetworkReply::bytesAvailable() + d->realFile->bytesAvailable(); } bool QNetworkReplyFileImpl::isSequential () const @@ -172,8 +202,9 @@ bool QNetworkReplyFileImpl::isSequential () const qint64 QNetworkReplyFileImpl::size() const { - Q_D(const QNetworkReplyFileImpl); - return d->realFileSize; + bool ok; + int size = header(QNetworkRequest::ContentLengthHeader).toInt(&ok); + return ok ? size : 0; } /*! @@ -182,11 +213,11 @@ qint64 QNetworkReplyFileImpl::size() const qint64 QNetworkReplyFileImpl::readData(char *data, qint64 maxlen) { Q_D(QNetworkReplyFileImpl); - if (!d->realFile.isOpen()) + if (!d->isFinished || !d->realFile || !d->realFile->isOpen()) return -1; - qint64 ret = d->realFile.read(data, maxlen); - if (bytesAvailable() == 0 && d->realFile.isOpen()) - d->realFile.close(); + qint64 ret = d->realFile->read(data, maxlen); + if (bytesAvailable() == 0) + d->realFile->close(); if (ret == 0 && bytesAvailable() == 0) return -1; else { @@ -196,6 +227,17 @@ qint64 QNetworkReplyFileImpl::readData(char *data, qint64 maxlen) } } +void QNetworkReplyFileImpl::fileOpenFinished(bool isOpen) +{ + setFinished(true); + if (isOpen) { + const auto fileSize = size(); + Q_EMIT metaDataChanged(); + Q_EMIT downloadProgress(fileSize, fileSize); + Q_EMIT readyRead(); + } + Q_EMIT finished(); +} QT_END_NAMESPACE diff --git a/src/network/access/qnetworkreplyfileimpl_p.h b/src/network/access/qnetworkreplyfileimpl_p.h index bac00881a8..1f1be40bc8 100644 --- a/src/network/access/qnetworkreplyfileimpl_p.h +++ b/src/network/access/qnetworkreplyfileimpl_p.h @@ -59,13 +59,12 @@ QT_BEGIN_NAMESPACE - class QNetworkReplyFileImplPrivate; class QNetworkReplyFileImpl: public QNetworkReply { Q_OBJECT public: - QNetworkReplyFileImpl(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op); + QNetworkReplyFileImpl(QNetworkAccessManager *manager, const QNetworkRequest &req, const QNetworkAccessManager::Operation op); ~QNetworkReplyFileImpl(); virtual void abort() Q_DECL_OVERRIDE; @@ -77,6 +76,9 @@ public: virtual qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; +private Q_SLOTS: + void fileOpenFinished(bool isOpen); + Q_DECLARE_PRIVATE(QNetworkReplyFileImpl) }; @@ -85,12 +87,14 @@ class QNetworkReplyFileImplPrivate: public QNetworkReplyPrivate public: QNetworkReplyFileImplPrivate(); - QFile realFile; - qint64 realFileSize; + QNetworkAccessManagerPrivate *managerPrivate; + QPointer<QFile> realFile; Q_DECLARE_PUBLIC(QNetworkReplyFileImpl) }; QT_END_NAMESPACE +Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders) + #endif // QNETWORKREPLYFILEIMPL_H diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index e1323527f6..6b77ab303f 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -617,17 +617,10 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq thread->setObjectName(QStringLiteral("Qt HTTP synchronous thread")); QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); - } else if (!managerPrivate->httpThread) { + } else { // We use the manager-global thread. // At some point we could switch to having multiple threads if it makes sense. - managerPrivate->httpThread = new QThread(); - managerPrivate->httpThread->setObjectName(QStringLiteral("Qt HTTP thread")); - managerPrivate->httpThread->start(); - - thread = managerPrivate->httpThread; - } else { - // Asynchronous request, thread already exists - thread = managerPrivate->httpThread; + thread = managerPrivate->createThread(); } QUrl url = newHttpRequest.url(); @@ -1137,8 +1130,8 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt cookedHeaders.clear(); - if (managerPrivate->httpThread) - managerPrivate->httpThread->disconnect(); + if (managerPrivate->thread) + managerPrivate->thread->disconnect(); // Recurse QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection, diff --git a/src/network/access/qspdyprotocolhandler.cpp b/src/network/access/qspdyprotocolhandler.cpp index 1a6dd04ecb..4641516549 100644 --- a/src/network/access/qspdyprotocolhandler.cpp +++ b/src/network/access/qspdyprotocolhandler.cpp @@ -458,7 +458,7 @@ bool QSpdyProtocolHandler::uncompressHeader(const QByteArray &input, QByteArray break; } default: { - qWarning() << "got unexpected zlib return value:" << zlibRet; + qWarning("got unexpected zlib return value: %d", zlibRet); return false; } } @@ -849,7 +849,7 @@ void QSpdyProtocolHandler::handleControlFrame(const QByteArray &frameHeaders) // break; } default: - qWarning() << "cannot handle frame of type" << type; + qWarning("cannot handle frame of type %d", int(type)); } } @@ -1085,7 +1085,7 @@ void QSpdyProtocolHandler::handleSETTINGS(char flags, quint32 /*length*/, const break; } default: - qWarning() << "found unknown settings value" << value; + qWarning("found unknown settings value %u", uint(value)); } } } @@ -1124,7 +1124,7 @@ void QSpdyProtocolHandler::handleGOAWAY(char /*flags*/, quint32 /*length*/, break; } default: - qWarning() << "unexpected status code" << statusCode; + qWarning("unexpected status code %d", int(statusCode)); errorCode = QNetworkReply::ProtocolUnknownError; } diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 78753a7393..10c0dccb9e 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -1453,15 +1453,9 @@ static bool q_NTLM_SSPI_library_load() if (pSecurityFunctionTable == NULL) { securityDLLHandle = LoadLibrary(L"secur32.dll"); if (securityDLLHandle != NULL) { -#if defined(Q_OS_WINCE) - INIT_SECURITY_INTERFACE pInitSecurityInterface = - (INIT_SECURITY_INTERFACE)GetProcAddress(securityDLLHandle, - L"InitSecurityInterfaceW"); -#else INIT_SECURITY_INTERFACE pInitSecurityInterface = (INIT_SECURITY_INTERFACE)GetProcAddress(securityDLLHandle, "InitSecurityInterfaceW"); -#endif if (pInitSecurityInterface != NULL) pSecurityFunctionTable = pInitSecurityInterface(); } diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 0dbe1112cd..757a6ad0b0 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE // sockaddr_in6 size changed between old and new SDK // Only the new version is the correct one, so always // use this structure. -#if defined(Q_OS_WINCE) || defined(Q_OS_WINRT) +#if defined(Q_OS_WINRT) # if !defined(u_char) # define u_char unsigned char # endif @@ -152,20 +152,37 @@ void QHostAddressPrivate::setAddress(quint32 a_) /// parses v4-mapped addresses or the AnyIPv6 address and stores in \a a; /// returns true if the address was one of those -static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6) +static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6, const QHostAddress::ConversionMode mode) { + if (mode == QHostAddress::StrictConversion) + return false; + const uchar *ptr = a6.c; if (qFromUnaligned<quint64>(ptr) != 0) return false; - if (qFromBigEndian<quint32>(ptr + 8) == 0) { - // is it AnyIPv6? - a = 0; - return qFromBigEndian<quint32>(ptr + 12) == 0; + + const quint32 mid = qFromBigEndian<quint32>(ptr + 8); + if ((mid == 0xffff) && (mode & QHostAddress::ConvertV4MappedToIPv4)) { + a = qFromBigEndian<quint32>(ptr + 12); + return true; } - if (qFromBigEndian<quint32>(ptr + 8) != 0xFFFF) + if (mid != 0) return false; - a = qFromBigEndian<quint32>(ptr + 12); - return true; + + const quint32 low = qFromBigEndian<quint32>(ptr + 12); + if ((low == 0) && (mode & QHostAddress::ConvertUnspecifiedAddress)) { + a = 0; + return true; + } + if ((low == 1) && (mode & QHostAddress::ConvertLocalHost)) { + a = INADDR_LOOPBACK; + return true; + } + if ((low != 1) && (mode & QHostAddress::ConvertV4CompatToIPv4)) { + a = low; + return true; + } + return false; } void QHostAddressPrivate::setAddress(const quint8 *a_) @@ -174,7 +191,8 @@ void QHostAddressPrivate::setAddress(const quint8 *a_) isParsed = true; memcpy(a6.c, a_, sizeof(a6)); a = 0; - convertToIpv4(a, a6); + convertToIpv4(a, a6, (QHostAddress::ConvertV4MappedToIPv4 + | QHostAddress::ConvertUnspecifiedAddress)); } void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_) @@ -386,6 +404,20 @@ void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol prot \value Any The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces. */ +/*! \enum QHostAddress::ConversionModeFlag + + \since 5.8 + + \value StrictConversion Don't convert IPv6 addresses to IPv4 when comparing two QHostAddress objects of different protocols, so they will always be considered different. + \value ConvertV4MappedToIPv4 Convert IPv4-mapped IPv6 addresses (RFC 4291 sect. 2.5.5.2) when comparing. Therefore QHostAddress("::ffff:192.168.1.1") will compare equal to QHostAddress("192.168.1.1"). + \value ConvertV4CompatToIPv4 Convert IPv4-compatible IPv6 addresses (RFC 4291 sect. 2.5.5.1) when comparing. Therefore QHostAddress("::192.168.1.1") will compare equal to QHostAddress("192.168.1.1"). + \value ConvertLocalHost Convert the IPv6 loopback addresses to its IPv4 equivalent when comparing. Therefore e.g. QHostAddress("::1") will compare equal to QHostAddress("127.0.0.1"). + \value ConvertUnspecifiedAddress All unspecified addresses will compare equal, namely AnyIPv4, AnyIPv6 and Any. + \value TolerantConversion Sets all three preceding flags. + + \sa isEqual() + */ + /*! Constructs a null host address object, i.e. an address which is not valid for any host or interface. \sa clear() @@ -691,7 +723,9 @@ quint32 QHostAddress::toIPv4Address(bool *ok) const quint32 dummy; if (ok) *ok = d->protocol == QAbstractSocket::IPv4Protocol || d->protocol == QAbstractSocket::AnyIPProtocol - || (d->protocol == QAbstractSocket::IPv6Protocol && convertToIpv4(dummy, d->a6)); + || (d->protocol == QAbstractSocket::IPv6Protocol + && convertToIpv4(dummy, d->a6, ConversionMode(QHostAddress::ConvertV4MappedToIPv4 + | QHostAddress::ConvertUnspecifiedAddress))); return d->a; } @@ -813,19 +847,73 @@ void QHostAddress::setScopeId(const QString &id) /*! Returns \c true if this host address is the same as the \a other address - given; otherwise returns \c false. + given; otherwise returns \c false. This operator just calls isEqual(other, StrictConversion). + + \sa isEqual() */ bool QHostAddress::operator==(const QHostAddress &other) const { + return isEqual(other, StrictConversion); +} + +/*! + \since 5.8 + + Returns \c true if this host address is the same as the \a other address + given; otherwise returns \c false. + + The parameter \a mode controls which conversions are preformed between addresses + of differing protocols. If no \a mode is given, \c TolerantConversion is performed + by default. + + \sa ConversionMode, operator==() + */ +bool QHostAddress::isEqual(const QHostAddress &other, ConversionMode mode) const +{ QT_ENSURE_PARSED(this); QT_ENSURE_PARSED(&other); - if (d->protocol == QAbstractSocket::IPv4Protocol) - return other.d->protocol == QAbstractSocket::IPv4Protocol && d->a == other.d->a; + if (d->protocol == QAbstractSocket::IPv4Protocol) { + switch (other.d->protocol) { + case QAbstractSocket::IPv4Protocol: + return d->a == other.d->a; + case QAbstractSocket::IPv6Protocol: + quint32 a4; + return convertToIpv4(a4, other.d->a6, mode) && (a4 == d->a); + case QAbstractSocket::AnyIPProtocol: + return (mode & QHostAddress::ConvertUnspecifiedAddress) && d->a == 0; + case QAbstractSocket::UnknownNetworkLayerProtocol: + return false; + } + } + if (d->protocol == QAbstractSocket::IPv6Protocol) { - return other.d->protocol == QAbstractSocket::IPv6Protocol - && memcmp(&d->a6, &other.d->a6, sizeof(Q_IPV6ADDR)) == 0; + switch (other.d->protocol) { + case QAbstractSocket::IPv4Protocol: + quint32 a4; + return convertToIpv4(a4, d->a6, mode) && (a4 == other.d->a); + case QAbstractSocket::IPv6Protocol: + return memcmp(&d->a6, &other.d->a6, sizeof(Q_IPV6ADDR)) == 0; + case QAbstractSocket::AnyIPProtocol: + return (mode & QHostAddress::ConvertUnspecifiedAddress) + && (other.d->a6_64.c[0] == 0) && (other.d->a6_64.c[1] == 0); + case QAbstractSocket::UnknownNetworkLayerProtocol: + return false; + } + } + + if ((d->protocol == QAbstractSocket::AnyIPProtocol) + && (mode & QHostAddress::ConvertUnspecifiedAddress)) { + switch (other.d->protocol) { + case QAbstractSocket::IPv4Protocol: + return other.d->a == 0; + case QAbstractSocket::IPv6Protocol: + return (other.d->a6_64.c[0] == 0) && (other.d->a6_64.c[1] == 0); + default: + break; + } } + return d->protocol == other.d->protocol; } diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h index 8236a71986..8cf6876511 100644 --- a/src/network/kernel/qhostaddress.h +++ b/src/network/kernel/qhostaddress.h @@ -79,6 +79,16 @@ public: AnyIPv6, AnyIPv4 }; + enum ConversionModeFlag { + ConvertV4MappedToIPv4 = 1, + ConvertV4CompatToIPv4 = 2, + ConvertUnspecifiedAddress = 4, + ConvertLocalHost = 8, + TolerantConversion = 0xff, + + StrictConversion = 0 + }; + Q_DECLARE_FLAGS(ConversionMode, ConversionModeFlag) QHostAddress(); explicit QHostAddress(quint32 ip4Addr); @@ -118,6 +128,7 @@ public: QString scopeId() const; void setScopeId(const QString &id); + bool isEqual(const QHostAddress &address, ConversionMode mode = TolerantConversion) const; bool operator ==(const QHostAddress &address) const; bool operator ==(SpecialAddress address) const; inline bool operator !=(const QHostAddress &address) const @@ -139,6 +150,7 @@ public: protected: QScopedPointer<QHostAddressPrivate> d; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QHostAddress::ConversionMode) Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QHostAddress) inline bool operator ==(QHostAddress::SpecialAddress address1, const QHostAddress &address2) diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp index cc6102a713..1d34ae8277 100644 --- a/src/network/kernel/qhostinfo_win.cpp +++ b/src/network/kernel/qhostinfo_win.cpp @@ -82,11 +82,7 @@ static void resolveLibrary() { // Attempt to resolve getaddrinfo(); without it we'll have to fall // back to gethostbyname(), which has no IPv6 support. -#if defined(Q_OS_WINCE) - local_getaddrinfo = (getaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "getaddrinfo"); - local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "freeaddrinfo"); - local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2"), "getnameinfo"); -#elif defined (Q_OS_WINRT) +#if defined (Q_OS_WINRT) local_getaddrinfo = (getaddrinfoProto) &getaddrinfo; local_freeaddrinfo = (freeaddrinfoProto) &freeaddrinfo; local_getnameinfo = (getnameinfoProto) getnameinfo; @@ -115,11 +111,6 @@ static void translateWSAError(int error, QHostInfo *results) QHostInfo QHostInfoAgent::fromName(const QString &hostName) { -#if defined(Q_OS_WINCE) - static QBasicMutex qPrivCEMutex; - QMutexLocker locker(&qPrivCEMutex); -#endif - QSysInfo::machineHostName(); // this initializes ws2_32.dll // Load res_init on demand. diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp index 0a82eac417..3002b2497b 100644 --- a/src/network/kernel/qnetworkinterface_win.cpp +++ b/src/network/kernel/qnetworkinterface_win.cpp @@ -81,19 +81,11 @@ static void resolveLibs() HINSTANCE iphlpapiHnd = GetModuleHandle(L"iphlpapi"); Q_ASSERT(iphlpapiHnd); -#if defined(Q_OS_WINCE) - // since Windows Embedded Compact 7 - ptrConvertInterfaceIndexToLuid = (PtrConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceIndexToLuid"); - ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceLuidToNameW"); - ptrConvertInterfaceLuidToIndex = (PtrConvertInterfaceLuidToIndex)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceLuidToIndex"); - ptrConvertInterfaceNameToLuid = (PtrConvertInterfaceNameToLuid)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceNameToLuidW"); -#else // since Windows Vista ptrConvertInterfaceIndexToLuid = (PtrConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHnd, "ConvertInterfaceIndexToLuid"); ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, "ConvertInterfaceLuidToNameW"); ptrConvertInterfaceLuidToIndex = (PtrConvertInterfaceLuidToIndex)GetProcAddress(iphlpapiHnd, "ConvertInterfaceLuidToIndex"); ptrConvertInterfaceNameToLuid = (PtrConvertInterfaceNameToLuid)GetProcAddress(iphlpapiHnd, "ConvertInterfaceNameToLuidW"); -#endif done = true; } } diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp index fe9f088062..a37585b5cd 100644 --- a/src/network/kernel/qnetworkproxy_win.cpp +++ b/src/network/kernel/qnetworkproxy_win.cpp @@ -53,7 +53,6 @@ #include <qt_windows.h> #include <wininet.h> #include <lmcons.h> -#include "qnetworkfunctions_wince.h" /* * Information on the WinHTTP DLL: @@ -123,7 +122,6 @@ static PtrWinHttpGetIEProxyConfigForCurrentUser ptrWinHttpGetIEProxyConfigForCur static PtrWinHttpCloseHandle ptrWinHttpCloseHandle = 0; -#ifndef Q_OS_WINCE static bool currentProcessIsService() { typedef BOOL (WINAPI *PtrGetUserName)(LPTSTR lpBuffer, LPDWORD lpnSize); @@ -153,7 +151,6 @@ static bool currentProcessIsService() } return false; } -#endif // ! Q_OS_WINCE static QStringList splitSpaceSemicolon(const QString &source) { @@ -359,7 +356,7 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con return removeDuplicateProxies(result); } -#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if !defined(Q_OS_WINRT) namespace { class QRegistryWatcher { public: @@ -410,7 +407,7 @@ private: QVector<HKEY> m_registryHandles; }; } // namespace -#endif // !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#endif // !defined(Q_OS_WINRT) class QWindowsSystemProxy { @@ -429,7 +426,7 @@ public: QStringList proxyServerList; QStringList proxyBypass; QList<QNetworkProxy> defaultResult; -#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if !defined(Q_OS_WINRT) QRegistryWatcher proxySettingsWatcher; #endif bool initialized; @@ -465,7 +462,7 @@ void QWindowsSystemProxy::reset() void QWindowsSystemProxy::init() { bool proxySettingsChanged = false; -#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if !defined(Q_OS_WINRT) proxySettingsChanged = proxySettingsWatcher.hasChanged(); #endif @@ -475,12 +472,7 @@ void QWindowsSystemProxy::init() reset(); -#ifdef Q_OS_WINCE - // Windows CE does not have any of the following API - return; -#else - -#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if !defined(Q_OS_WINRT) proxySettingsWatcher.clear(); // needs reset to trigger a new detection proxySettingsWatcher.addLocation(HKEY_CURRENT_USER, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings")); proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings")); @@ -568,7 +560,6 @@ void QWindowsSystemProxy::init() } functional = isAutoConfig || !proxyServerList.isEmpty(); -#endif } QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 802b623375..03f2ddb968 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -563,6 +563,7 @@ QAbstractSocketPrivate::QAbstractSocketPrivate() cachedSocketDescriptor(-1), readBufferMaxSize(0), isBuffered(false), + hasPendingData(false), connectTimer(0), disconnectTimer(0), hostLookupId(-1), @@ -593,6 +594,7 @@ void QAbstractSocketPrivate::resetSocketLayer() qDebug("QAbstractSocketPrivate::resetSocketLayer()"); #endif + hasPendingData = false; if (socketEngine) { socketEngine->close(); socketEngine->disconnect(); @@ -683,14 +685,20 @@ bool QAbstractSocketPrivate::canReadNotification() qDebug("QAbstractSocketPrivate::canReadNotification()"); #endif - if (!isBuffered) - socketEngine->setReadNotificationEnabled(false); + if (!isBuffered) { + if (hasPendingData) { + socketEngine->setReadNotificationEnabled(false); + return true; + } + hasPendingData = true; + } // If buffered, read data from the socket into the read buffer qint64 newBytes = 0; if (isBuffered) { // Return if there is no space in the buffer if (readBufferMaxSize && buffer.size() >= readBufferMaxSize) { + socketEngine->setReadNotificationEnabled(false); #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canReadNotification() buffer is full"); #endif @@ -708,11 +716,6 @@ bool QAbstractSocketPrivate::canReadNotification() return false; } newBytes = buffer.size() - newBytes; - - // If read buffer is full, disable the read socket notifier. - if (readBufferMaxSize && buffer.size() == readBufferMaxSize) { - socketEngine->setReadNotificationEnabled(false); - } } // Only emit readyRead() if there is data available. @@ -728,10 +731,6 @@ bool QAbstractSocketPrivate::canReadNotification() return true; } - // turn the socket engine off if we've reached the buffer size limit - if (socketEngine && isBuffered) - socketEngine->setReadNotificationEnabled(readBufferMaxSize == 0 || readBufferMaxSize > q->bytesAvailable()); - return true; } @@ -788,12 +787,8 @@ bool QAbstractSocketPrivate::canWriteNotification() #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canWriteNotification() flushing"); #endif - bool dataWasWritten = writeToSocket(); - - if (socketEngine && writeBuffer.isEmpty() && socketEngine->bytesToWrite() == 0) - socketEngine->setWriteNotificationEnabled(false); - return dataWasWritten; + return writeToSocket(); } /*! \internal @@ -833,8 +828,12 @@ bool QAbstractSocketPrivate::writeToSocket() #endif // this covers the case when the buffer was empty, but we had to wait for the socket engine to finish - if (state == QAbstractSocket::ClosingState) + if (state == QAbstractSocket::ClosingState) { q->disconnectFromHost(); + } else { + if (socketEngine) + socketEngine->setWriteNotificationEnabled(false); + } return false; } @@ -872,8 +871,7 @@ bool QAbstractSocketPrivate::writeToSocket() emit q->channelBytesWritten(0, written); } - if (writeBuffer.isEmpty() && socketEngine && socketEngine->isWriteNotificationEnabled() - && !socketEngine->bytesToWrite()) + if (writeBuffer.isEmpty() && socketEngine && !socketEngine->bytesToWrite()) socketEngine->setWriteNotificationEnabled(false); if (state == QAbstractSocket::ClosingState) q->disconnectFromHost(); @@ -1144,12 +1142,10 @@ void QAbstractSocketPrivate::_q_connectToNextAddress() */ void QAbstractSocketPrivate::_q_testConnection() { - if (socketEngine) { - if (threadData->hasEventDispatcher()) { - if (connectTimer) - connectTimer->stop(); - } + if (connectTimer) + connectTimer->stop(); + if (socketEngine) { if (socketEngine->state() == QAbstractSocket::ConnectedState) { // Fetch the parameters if our connection is completed; // otherwise, fall out and try the next address. @@ -1166,11 +1162,6 @@ void QAbstractSocketPrivate::_q_testConnection() addresses.clear(); } - if (threadData->hasEventDispatcher()) { - if (connectTimer) - connectTimer->stop(); - } - #if defined(QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::_q_testConnection() connection failed," " checking for alternative addresses"); @@ -2379,11 +2370,6 @@ void QAbstractSocket::abort() return; } #endif - if (d->connectTimer) { - d->connectTimer->stop(); - delete d->connectTimer; - d->connectTimer = 0; - } d->abortCalled = true; close(); @@ -2430,15 +2416,7 @@ bool QAbstractSocket::atEnd() const // Note! docs copied to QSslSocket::flush() bool QAbstractSocket::flush() { - Q_D(QAbstractSocket); -#ifndef QT_NO_SSL - // Manual polymorphism; flush() isn't virtual, but QSslSocket overloads - // it. - if (QSslSocket *socket = qobject_cast<QSslSocket *>(this)) - return socket->flush(); -#endif - Q_CHECK_SOCKETENGINE(false); - return d->flush(); + return d_func()->flush(); } /*! \reimp @@ -2461,8 +2439,9 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize) d->setError(d->socketEngine->error(), d->socketEngine->errorString()); d->resetSocketLayer(); d->state = QAbstractSocket::UnconnectedState; - } else if (!d->socketEngine->isReadNotificationEnabled()) { + } else { // Only do this when there was no error + d->hasPendingData = false; d->socketEngine->setReadNotificationEnabled(true); } @@ -2828,12 +2807,12 @@ void QAbstractSocket::setReadBufferSize(qint64 size) if (d->readBufferMaxSize == size) return; d->readBufferMaxSize = size; - if (!d->emittedReadyRead && d->socketEngine) { - // ensure that the read notification is enabled if we've now got - // room in the read buffer - // but only if we're not inside canReadNotification -- that will take care on its own - if ((size == 0 || d->buffer.size() < size) && d->state == QAbstractSocket::ConnectedState) // Do not change the notifier unless we are connected. - d->socketEngine->setReadNotificationEnabled(true); + + // Do not change the notifier unless we are connected. + if (d->socketEngine && d->state == QAbstractSocket::ConnectedState) { + // Ensure that the read notification is enabled if we've now got + // room in the read buffer. + d->socketEngine->setReadNotificationEnabled(size == 0 || d->buffer.size() < size); } } diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index b718c21ff5..3164c96c1e 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -128,13 +128,12 @@ public: inline void resolveProxy(quint16 port) { resolveProxy(QString(), port); } void resetSocketLayer(); - bool flush(); + virtual bool flush(); bool initSocketLayer(QAbstractSocket::NetworkLayerProtocol protocol); virtual void configureCreatedSocket(); void startConnectingByName(const QString &host); void fetchConnectionParameters(); - void setupSocketNotifiers(); bool readFromSocket(); bool writeToSocket(); void emitReadyRead(); @@ -144,6 +143,7 @@ public: qint64 readBufferMaxSize; bool isBuffered; + bool hasPendingData; QTimer *connectTimer; QTimer *disconnectTimer; diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 19e9e1d9b7..5a05d7c98c 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -66,21 +66,20 @@ QT_BEGIN_NAMESPACE #ifdef Q_OS_WIN -#define QT_SOCKLEN_T int -#define QT_SOCKOPTLEN_T int +# define QT_SOCKLEN_T int +# define QT_SOCKOPTLEN_T int // The following definitions are copied from the MinGW header mswsock.h which // was placed in the public domain. The WSASendMsg and WSARecvMsg functions // were introduced with Windows Vista, so some Win32 headers are lacking them. // There are no known versions of Windows CE or Embedded that contain them. -#ifndef Q_OS_WINCE # ifndef WSAID_WSARECVMSG typedef INT (WINAPI *LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg, LPDWORD lpdwNumberOfBytesRecvd, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); # define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} -# endif +# endif // !WSAID_WSARECVMSG # ifndef WSAID_WSASENDMSG typedef struct { LPWSAMSG lpMsg; @@ -96,9 +95,8 @@ typedef INT (WSAAPI *LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); # define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} -# endif -#endif -#endif +# endif // !WSAID_WSASENDMSG +#endif // Q_OS_WIN union qt_sockaddr { sockaddr a; @@ -210,7 +208,7 @@ public: QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_WIN) LPFN_WSASENDMSG sendmsg; LPFN_WSARECVMSG recvmsg; # endif diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 648f2bf376..07f4899bae 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -387,7 +387,6 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc return false; } -#if !defined(Q_OS_WINCE) if (socketType == QAbstractSocket::UdpSocket) { // enable new behavior using // SIO_UDP_CONNRESET @@ -414,7 +413,6 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc &sendmsgguid, sizeof(sendmsgguid), &sendmsg, sizeof(sendmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR) sendmsg = 0; -#endif socketDescriptor = socket; if (socket != INVALID_SOCKET) { @@ -1078,7 +1076,6 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const { -#if !defined(Q_OS_WINCE) // Create a sockaddr struct and reset its port number. qt_sockaddr storage; QT_SOCKLEN_T storageSize = sizeof(storage); @@ -1105,18 +1102,6 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const result = true; } -#else // Q_OS_WINCE - bool result = false; - fd_set readS; - FD_ZERO(&readS); - FD_SET((SOCKET)socketDescriptor, &readS); - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 5000; - int available = ::select(1, &readS, 0, 0, &timeout); - result = available > 0; -#endif - #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s", result ? "true" : "false"); @@ -1128,7 +1113,6 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { qint64 ret = -1; -#if !defined(Q_OS_WINCE) int recvResult = 0; DWORD flags; DWORD bufferCount = 5; @@ -1173,18 +1157,6 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const if (buf) delete[] buf; -#else // Q_OS_WINCE - DWORD size = -1; - DWORD bytesReturned; - int ioResult = WSAIoctl(socketDescriptor, FIONREAD, 0,0, &size, sizeof(size), &bytesReturned, 0, 0); - if (ioResult == SOCKET_ERROR) { - int err = WSAGetLastError(); - WS_ERROR_DEBUG(err); - } else { - ret = qint64(size); - } -#endif - #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %li", ret); #endif @@ -1192,12 +1164,6 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const return ret; } -#ifdef Q_OS_WINCE -// Windows CE has no support for sendmsg or recvmsg. We set it to null here to simplify the code below. -static int (*const recvmsg)(...) = 0; -static int (*const sendmsg)(...) = 0; -#endif - qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header, QAbstractSocketEngine::PacketHeaderOptions options) { @@ -1316,12 +1282,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l memset(&msg, 0, sizeof(msg)); memset(&aa, 0, sizeof(aa)); -#if !defined(Q_OS_WINCE) buf.buf = len ? (char*)data : 0; -#else - char tmp; - buf.buf = len ? (char*)data : &tmp; -#endif msg.lpBuffers = &buf; msg.dwBufferCount = 1; msg.name = &aa.a; @@ -1482,9 +1443,6 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength) buf.len = maxLength; DWORD flags = 0; DWORD bytesRead = 0; -#if defined(Q_OS_WINCE) - WSASetLastError(0); -#endif if (::WSARecv(socketDescriptor, &buf, 1, &bytesRead, &flags, 0,0) == SOCKET_ERROR) { int err = WSAGetLastError(); WS_ERROR_DEBUG(err); @@ -1598,11 +1556,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; -#if !defined(Q_OS_WINCE) ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); -#else - ret = select(1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); -#endif //... but if it is actually set, pretend it did not happen if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception)) diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index 0c15810a48..369396271e 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -64,11 +64,7 @@ static const int MaxWriteBufferSize = 128*1024; //#define QSOCKS5SOCKETLAYER_DEBUG #define MAX_DATA_DUMP 256 -#if !defined(Q_OS_WINCE) #define SOCKS5_BLOCKING_BIND_TIMEOUT 5000 -#else -#define SOCKS5_BLOCKING_BIND_TIMEOUT 10000 -#endif #define Q_INIT_CHECK(returnValue) do { \ if (!d->data) { \ diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index 7dd884c16a..809b603403 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -543,8 +543,11 @@ QTcpSocket *QTcpServer::nextPendingConnection() if (d->pendingConnections.isEmpty()) return 0; - if (!d->socketEngine->isReadNotificationEnabled()) + if (!d->socketEngine) { + qWarning("QTcpServer::nextPendingConnection() called while not listening"); + } else if (!d->socketEngine->isReadNotificationEnabled()) { d->socketEngine->setReadNotificationEnabled(true); + } return d->pendingConnections.takeFirst(); } diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index c406009069..083648bc23 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -398,7 +398,8 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres readBytes = d->socketEngine->readDatagram(data, maxSize); } - d_func()->socketEngine->setReadNotificationEnabled(true); + d->hasPendingData = false; + d->socketEngine->setReadNotificationEnabled(true); if (readBytes < 0) d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString()); return readBytes; diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index f50a7b1229..2d80f38bec 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -43,7 +43,7 @@ win32:!winrt:SOURCES += socket/qnativesocketengine_win.cpp \ socket/qlocalsocket_win.cpp \ socket/qlocalserver_win.cpp -win32:!wince:!winrt:LIBS_PRIVATE += -ladvapi32 +win32:!winrt:LIBS_PRIVATE += -ladvapi32 winrt { SOURCES += socket/qnativesocketengine_winrt.cpp \ @@ -54,15 +54,6 @@ winrt { DEFINES += QT_LOCALSOCKET_TCP } -wince { - SOURCES -= socket/qlocalsocket_win.cpp \ - socket/qlocalserver_win.cpp - SOURCES += socket/qlocalsocket_tcp.cpp \ - socket/qlocalserver_tcp.cpp - - DEFINES += QT_LOCALSOCKET_TCP -} - integrity: { SOURCES -= socket/qlocalsocket_unix.cpp \ socket/qlocalserver_unix.cpp diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index f9bb28e033..1eb253d202 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -119,7 +119,8 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1"; /*! \enum QSslConfiguration::NextProtocolNegotiationStatus - Describes the status of the Next Protocol Negotiation (NPN). + Describes the status of the Next Protocol Negotiation (NPN) or + Application-Layer Protocol Negotiation (ALPN). \value NextProtocolNegotiationNone No application protocol has been negotiated (yet). @@ -209,6 +210,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->privateKey == other.d->privateKey && d->sessionCipher == other.d->sessionCipher && d->sessionProtocol == other.d->sessionProtocol && + d->preSharedKeyIdentityHint == other.d->preSharedKeyIdentityHint && d->ciphers == other.d->ciphers && d->ellipticCurves == other.d->ellipticCurves && d->caCertificates == other.d->caCertificates && @@ -259,6 +261,7 @@ bool QSslConfiguration::isNull() const d->sslOptions == QSslConfigurationPrivate::defaultSslOptions && d->sslSession.isNull() && d->sslSessionTicketLifeTimeHint == -1 && + d->preSharedKeyIdentityHint.isNull() && d->nextAllowedProtocols.isEmpty() && d->nextNegotiatedProtocol.isNull() && d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone); @@ -809,11 +812,38 @@ QVector<QSslEllipticCurve> QSslConfiguration::supportedEllipticCurves() } /*! + \since 5.8 + + Returns the identity hint. + + \sa setPreSharedKeyIdentityHint() +*/ +QByteArray QSslConfiguration::preSharedKeyIdentityHint() const +{ + return d->preSharedKeyIdentityHint; +} + +/*! + \since 5.8 + + Sets the identity hint for a preshared key authentication. This will affect the next + initiated handshake; calling this function on an already-encrypted socket + will not affect the socket's identity hint. + + The identity hint is used in QSslSocket::SslServerMode only! +*/ +void QSslConfiguration::setPreSharedKeyIdentityHint(const QByteArray &hint) +{ + d->preSharedKeyIdentityHint = hint; +} + +/*! \since 5.3 This function returns the protocol negotiated with the server - if the Next Protocol Negotiation (NPN) TLS extension was enabled. - In order for the NPN extension to be enabled, setAllowedNextProtocols() + if the Next Protocol Negotiation (NPN) or Application-Layer Protocol + Negotiation (ALPN) TLS extension was enabled. + In order for the NPN/ALPN extension to be enabled, setAllowedNextProtocols() needs to be called explicitly before connecting to the server. If no protocol could be negotiated or the extension was not enabled, @@ -830,9 +860,10 @@ QByteArray QSslConfiguration::nextNegotiatedProtocol() const \since 5.3 This function sets the allowed \a protocols to be negotiated with the - server through the Next Protocol Negotiation (NPN) TLS extension; each + server through the Next Protocol Negotiation (NPN) or Application-Layer + Protocol Negotiation (ALPN) TLS extension; each element in \a protocols must define one allowed protocol. - The function must be called explicitly before connecting to send the NPN + The function must be called explicitly before connecting to send the NPN/ALPN extension in the SSL handshake. Whether or not the negotiation succeeded can be queried through nextProtocolNegotiationStatus(). @@ -852,8 +883,8 @@ void QSslConfiguration::setAllowedNextProtocols(QList<QByteArray> protocols) \since 5.3 This function returns the allowed protocols to be negotiated with the - server through the Next Protocol Negotiation (NPN) TLS extension, as set - by setAllowedNextProtocols(). + server through the Next Protocol Negotiation (NPN) or Application-Layer + Protocol Negotiation (ALPN) TLS extension, as set by setAllowedNextProtocols(). \sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1 */ @@ -865,7 +896,8 @@ QList<QByteArray> QSslConfiguration::allowedNextProtocols() const /*! \since 5.3 - This function returns the status of the Next Protocol Negotiation (NPN). + This function returns the status of the Next Protocol Negotiation (NPN) + or Application-Layer Protocol Negotiation (ALPN). If the feature has not been enabled through setAllowedNextProtocols(), this function returns NextProtocolNegotiationNone. The status will be set before emitting the encrypted() signal. diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index f0754d7ef5..1f39e1a06f 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -141,6 +141,9 @@ public: void setEllipticCurves(const QVector<QSslEllipticCurve> &curves); static QVector<QSslEllipticCurve> supportedEllipticCurves(); + QByteArray preSharedKeyIdentityHint() const; + void setPreSharedKeyIdentityHint(const QByteArray &hint); + static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h index 093c9d6598..113954d7d1 100644 --- a/src/network/ssl/qsslconfiguration_p.h +++ b/src/network/ssl/qsslconfiguration_p.h @@ -88,6 +88,7 @@ public: peerSessionShared(false), sslOptions(QSslConfigurationPrivate::defaultSslOptions), sslSessionTicketLifeTimeHint(-1), + preSharedKeyIdentityHint(), nextProtocolNegotiationStatus(QSslConfiguration::NextProtocolNegotiationNone) { } @@ -121,6 +122,8 @@ public: QSslKey ephemeralServerKey; + QByteArray preSharedKeyIdentityHint; + QList<QByteArray> nextAllowedProtocols; QByteArray nextNegotiatedProtocol; QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus; diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp index b3786f989e..0db7e10409 100644 --- a/src/network/ssl/qsslcontext_openssl.cpp +++ b/src/network/ssl/qsslcontext_openssl.cpp @@ -344,6 +344,11 @@ init_context: } #endif // OPENSSL_NO_EC +#ifndef OPENSSL_NO_PSK + if (!client) + q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData()); +#endif // OPENSSL_NO_PSK + const QVector<QSslEllipticCurve> qcurves = sslContext->sslConfiguration.ellipticCurves(); if (!qcurves.isEmpty()) { #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC) @@ -457,6 +462,23 @@ SSL* QSslContext::createSsl() m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data()); m_npnContext.len = m_supportedNPNVersions.count(); m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone; +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (q_SSLeay() >= 0x10002000L) { + // Callback's type has a parameter 'const unsigned char ** out' + // since it was introduced in 1.0.2. Internally, OpenSSL's own code + // (tests/examples) cast it to unsigned char * (since it's 'out'). + // We just re-use our NPN callback and cast here: + typedef int (*alpn_callback_t) (SSL *, const unsigned char **, unsigned char *, + const unsigned char *, unsigned int, void *); + // With ALPN callback is for a server side only, for a client m_npnContext.status + // will stay in NextProtocolNegotiationNone. + q_SSL_CTX_set_alpn_select_cb(ctx, alpn_callback_t(next_proto_cb), &m_npnContext); + // Client: + q_SSL_set_alpn_protos(ssl, m_npnContext.data, m_npnContext.len); + } +#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ... + + // And in case our peer does not support ALPN, but supports NPN: q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext); } #endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ... diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 3e7a30aa9f..82df861859 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -836,15 +836,7 @@ bool QSslSocket::atEnd() const // Note! docs copied from QAbstractSocket::flush() bool QSslSocket::flush() { - Q_D(QSslSocket); -#ifdef QSSLSOCKET_DEBUG - qCDebug(lcSsl) << "QSslSocket::flush()"; -#endif - if (d->mode != UnencryptedMode) - // encrypt any unencrypted bytes in our buffer - d->transmit(); - - return d->plainSocket ? d->plainSocket->flush() : false; + return d_func()->flush(); } /*! @@ -923,6 +915,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.privateKey = configuration.privateKey(); d->configuration.ciphers = configuration.ciphers(); d->configuration.ellipticCurves = configuration.ellipticCurves(); + d->configuration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint(); d->configuration.caCertificates = configuration.caCertificates(); d->configuration.peerVerifyDepth = configuration.peerVerifyDepth(); d->configuration.peerVerifyMode = configuration.peerVerifyMode(); @@ -2614,6 +2607,22 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize) /*! \internal */ +bool QSslSocketPrivate::flush() +{ +#ifdef QSSLSOCKET_DEBUG + qCDebug(lcSsl) << "QSslSocketPrivate::flush()"; +#endif + if (mode != QSslSocket::UnencryptedMode) { + // encrypt any unencrypted bytes in our buffer + transmit(); + } + + return plainSocket && plainSocket->flush(); +} + +/*! + \internal +*/ bool QSslSocketPrivate::rootCertOnDemandLoadingSupported() { return s_loadRootCertsOnDemand; diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h index c069ff2f9d..1f2ed7687b 100644 --- a/src/network/ssl/qsslsocket.h +++ b/src/network/ssl/qsslsocket.h @@ -116,7 +116,7 @@ public: bool canReadLine() const Q_DECL_OVERRIDE; void close() Q_DECL_OVERRIDE; bool atEnd() const Q_DECL_OVERRIDE; - bool flush(); + bool flush(); // ### Qt6: remove me (implementation moved to private flush()) void abort(); // From QAbstractSocket: diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 4f62f53a93..5cbd2af323 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -201,6 +201,15 @@ static unsigned int q_ssl_psk_client_callback(SSL *ssl, Q_ASSERT(d); return d->tlsPskClientCallback(hint, identity, max_identity_len, psk, max_psk_len); } + +static unsigned int q_ssl_psk_server_callback(SSL *ssl, + const char *identity, + unsigned char *psk, unsigned int max_psk_len) +{ + QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData)); + Q_ASSERT(d); + return d->tlsPskServerCallback(identity, psk, max_psk_len); +} #endif } // extern "C" @@ -436,8 +445,12 @@ bool QSslSocketBackendPrivate::initSslContext() #if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK) // Set the client callback for PSK - if (q_SSLeay() >= 0x10001000L && mode == QSslSocket::SslClientMode) - q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback); + if (q_SSLeay() >= 0x10001000L) { + if (mode == QSslSocket::SslClientMode) + q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback); + else if (mode == QSslSocket::SslServerMode) + q_SSL_set_psk_server_callback(ssl, &q_ssl_psk_server_callback); + } #endif return true; @@ -522,15 +535,9 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if defined(Q_OS_WIN) HINSTANCE hLib = LoadLibraryW(L"Crypt32"); if (hLib) { -#if defined(Q_OS_WINCE) - ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, L"CertOpenStore"); - ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, L"CertFindCertificateInStore"); - ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, L"CertCloseStore"); -#else ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW"); ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore"); ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore"); -#endif if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen } else { @@ -691,15 +698,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() #if defined(Q_OS_WIN) if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) { HCERTSTORE hSystemStore; -#if defined(Q_OS_WINCE) - hSystemStore = ptrCertOpenSystemStoreW(CERT_STORE_PROV_SYSTEM_W, - 0, - 0, - CERT_STORE_NO_CRYPT_RELEASE_FLAG|CERT_SYSTEM_STORE_CURRENT_USER, - L"ROOT"); -#else hSystemStore = ptrCertOpenSystemStoreW(0, L"ROOT"); -#endif if(hSystemStore) { PCCERT_CONTEXT pc = NULL; while(1) { @@ -1274,6 +1273,31 @@ unsigned int QSslSocketBackendPrivate::tlsPskClientCallback(const char *hint, return pskLength; } +unsigned int QSslSocketBackendPrivate::tlsPskServerCallback(const char *identity, + unsigned char *psk, unsigned int max_psk_len) +{ + QSslPreSharedKeyAuthenticator authenticator; + + // Fill in some read-only fields (for the user) + authenticator.d->identityHint = configuration.preSharedKeyIdentityHint; + authenticator.d->identity = identity; + authenticator.d->maximumIdentityLength = 0; // user cannot set an identity + authenticator.d->maximumPreSharedKeyLength = int(max_psk_len); + + // Let the client provide the remaining bits... + Q_Q(QSslSocket); + emit q->preSharedKeyAuthenticationRequired(&authenticator); + + // No PSK set? Return now to make the handshake fail + if (authenticator.preSharedKey().isEmpty()) + return 0; + + // Copy data back into OpenSSL + const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength()); + ::memcpy(psk, authenticator.preSharedKey().constData(), pskLength); + return pskLength; +} + #ifdef Q_OS_WIN void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert) @@ -1571,7 +1595,22 @@ void QSslSocketBackendPrivate::continueHandshake() } else { const unsigned char *proto = 0; unsigned int proto_len = 0; - q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (q_SSLeay() >= 0x10002000L) { + q_SSL_get0_alpn_selected(ssl, &proto, &proto_len); + if (proto_len && mode == QSslSocket::SslClientMode) { + // Client does not have a callback that sets it ... + configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated; + } + } + + if (!proto_len) { // Test if NPN was more lucky ... +#else + { +#endif + q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len); + } + if (proto_len) configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len); else diff --git a/src/network/ssl/qsslsocket_openssl_android.cpp b/src/network/ssl/qsslsocket_openssl_android.cpp index d73ed8995e..b5d2458d56 100644 --- a/src/network/ssl/qsslsocket_openssl_android.cpp +++ b/src/network/ssl/qsslsocket_openssl_android.cpp @@ -70,6 +70,7 @@ QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData() QJNIEnvironmentPrivate env; jobjectArray jcertificates = static_cast<jobjectArray>(certificates.object()); const jint nCertificates = env->GetArrayLength(jcertificates); + certificateData.reserve(static_cast<int>(nCertificates)); for (int i = 0; i < nCertificates; ++i) { jbyteArray jCert = static_cast<jbyteArray>(env->GetObjectArrayElement(jcertificates, i)); diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index 0674c05d71..c6572315f0 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -143,6 +143,7 @@ public: bool checkSslErrors(); void storePeerCertificates(); unsigned int tlsPskClientCallback(const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len); + unsigned int tlsPskServerCallback(const char *identity, unsigned char *psk, unsigned int max_psk_len); #ifdef Q_OS_WIN void fetchCaRootForCert(const QSslCertificate &cert); void _q_caRootLoaded(QSslCertificate,QSslCertificate) Q_DECL_OVERRIDE; diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index d0982377fb..f625fd3e96 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -300,6 +300,8 @@ DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return N #endif #if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK) DEFINEFUNC2(void, SSL_set_psk_client_callback, SSL* ssl, ssl, q_psk_client_callback_t callback, callback, return, DUMMYARG) +DEFINEFUNC2(void, SSL_set_psk_server_callback, SSL* ssl, ssl, q_psk_server_callback_t callback, callback, return, DUMMYARG) +DEFINEFUNC2(int, SSL_CTX_use_psk_identity_hint, SSL_CTX* ctx, ctx, const char *hint, hint, return 0, return) #endif #if OPENSSL_VERSION_NUMBER >= 0x10000000L #ifndef OPENSSL_NO_SSL2 @@ -418,6 +420,18 @@ DEFINEFUNC3(void, SSL_CTX_set_next_proto_select_cb, SSL_CTX *s, s, void *arg, arg, return, DUMMYARG) DEFINEFUNC3(void, SSL_get0_next_proto_negotiated, const SSL *s, s, const unsigned char **data, data, unsigned *len, len, return, DUMMYARG) +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +DEFINEFUNC3(int, SSL_set_alpn_protos, SSL *s, s, const unsigned char *protos, protos, + unsigned protos_len, protos_len, return -1, return) +DEFINEFUNC3(void, SSL_CTX_set_alpn_select_cb, SSL_CTX *s, s, + int (*cb) (SSL *ssl, const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, void *arg), cb, + void *arg, arg, return, DUMMYARG) +DEFINEFUNC3(void, SSL_get0_alpn_selected, const SSL *s, s, const unsigned char **data, data, + unsigned *len, len, return, DUMMYARG) +#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ... #endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ... DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return 0, return) DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG) @@ -889,6 +903,8 @@ bool q_resolveOpenSslSymbols() #endif #if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK) RESOLVEFUNC(SSL_set_psk_client_callback) + RESOLVEFUNC(SSL_set_psk_server_callback) + RESOLVEFUNC(SSL_CTX_use_psk_identity_hint) #endif RESOLVEFUNC(SSL_write) #ifndef OPENSSL_NO_SSL2 diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 36e041b6cb..45e4380580 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -376,6 +376,9 @@ void *q_SSL_get_ex_data(const SSL *ssl, int idx); #ifndef OPENSSL_NO_PSK typedef unsigned int (*q_psk_client_callback_t)(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len); void q_SSL_set_psk_client_callback(SSL *ssl, q_psk_client_callback_t callback); +typedef unsigned int (*q_psk_server_callback_t)(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len); +void q_SSL_set_psk_server_callback(SSL *ssl, q_psk_server_callback_t callback); +int q_SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint); #endif // OPENSSL_NO_PSK #if OPENSSL_VERSION_NUMBER >= 0x10000000L #ifndef OPENSSL_NO_SSL2 @@ -558,6 +561,19 @@ void q_SSL_CTX_set_next_proto_select_cb(SSL_CTX *s, void *arg); void q_SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +int q_SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos, + unsigned protos_len); +void q_SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg); +void q_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, + unsigned *len); +#endif #endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ... // Helper function diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 5d4d52cd6d..e791b9d166 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -89,11 +89,7 @@ QT_BEGIN_NAMESPACE #endif #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -#if defined(Q_OS_WINCE) - typedef HCERTSTORE (WINAPI *PtrCertOpenSystemStoreW)(LPCSTR, DWORD, HCRYPTPROV_LEGACY, DWORD, const void*); -#else typedef HCERTSTORE (WINAPI *PtrCertOpenSystemStoreW)(HCRYPTPROV_LEGACY, LPCWSTR); -#endif typedef PCCERT_CONTEXT (WINAPI *PtrCertFindCertificateInStore)(HCERTSTORE, DWORD, DWORD, DWORD, const void*, PCCERT_CONTEXT); typedef BOOL (WINAPI *PtrCertCloseStore)(HCERTSTORE, DWORD); #endif // Q_OS_WIN && !Q_OS_WINRT @@ -193,6 +189,7 @@ public: virtual qint64 peek(char *data, qint64 maxSize) Q_DECL_OVERRIDE; virtual QByteArray peek(qint64 maxSize) Q_DECL_OVERRIDE; + bool flush() Q_DECL_OVERRIDE; // Platform specific functions virtual void startClientEncryption() = 0; diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp index 045c89eb0e..5704d6b151 100644 --- a/src/network/ssl/qsslsocket_winrt.cpp +++ b/src/network/ssl/qsslsocket_winrt.cpp @@ -215,7 +215,9 @@ QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers() const QString protocolStrings[] = { QStringLiteral("SSLv3"), QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"), QStringLiteral("TLSv1.2") }; const QSsl::SslProtocol protocols[] = { QSsl::SslV3, QSsl::TlsV1_0, QSsl::TlsV1_1, QSsl::TlsV1_2 }; - for (int i = 0; i < ARRAYSIZE(protocols); ++i) { + const int size = static_cast<int>(ARRAYSIZE(protocols)); + ciphers.reserve(size); + for (int i = 0; i < size; ++i) { QSslCipher cipher; cipher.d->isNull = false; cipher.d->name = QStringLiteral("WINRT"); |