diff options
Diffstat (limited to 'src/network')
115 files changed, 2475 insertions, 706 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri index e8669dcec8..1d6a04a424 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -1,14 +1,6 @@ # Qt network access module HEADERS += \ - access/qhttpnetworkheader_p.h \ - access/qhttpnetworkrequest_p.h \ - access/qhttpnetworkreply_p.h \ - access/qhttpnetworkconnection_p.h \ - access/qhttpnetworkconnectionchannel_p.h \ - access/qabstractprotocolhandler_p.h \ - access/qhttpprotocolhandler_p.h \ - access/qspdyprotocolhandler_p.h \ access/qnetworkaccessauthenticationmanager_p.h \ access/qnetworkaccessmanager.h \ access/qnetworkaccessmanager_p.h \ @@ -27,28 +19,15 @@ HEADERS += \ access/qnetworkreply_p.h \ access/qnetworkreplyimpl_p.h \ access/qnetworkreplydataimpl_p.h \ - access/qnetworkreplyhttpimpl_p.h \ access/qnetworkreplyfileimpl_p.h \ access/qabstractnetworkcache_p.h \ access/qabstractnetworkcache.h \ - access/qhttpthreaddelegate_p.h \ - access/qhttpmultipart.h \ - access/qhttpmultipart_p.h \ access/qnetworkfile_p.h \ - access/qhttp2protocolhandler_p.h \ access/qhsts_p.h \ access/qhstspolicy.h \ access/qhstsstore_p.h SOURCES += \ - access/qhttpnetworkheader.cpp \ - access/qhttpnetworkrequest.cpp \ - access/qhttpnetworkreply.cpp \ - access/qhttpnetworkconnection.cpp \ - access/qhttpnetworkconnectionchannel.cpp \ - access/qabstractprotocolhandler.cpp \ - access/qhttpprotocolhandler.cpp \ - access/qspdyprotocolhandler.cpp \ access/qnetworkaccessauthenticationmanager.cpp \ access/qnetworkaccessmanager.cpp \ access/qnetworkaccesscache.cpp \ @@ -62,13 +41,9 @@ SOURCES += \ access/qnetworkreply.cpp \ access/qnetworkreplyimpl.cpp \ access/qnetworkreplydataimpl.cpp \ - access/qnetworkreplyhttpimpl.cpp \ access/qnetworkreplyfileimpl.cpp \ access/qabstractnetworkcache.cpp \ - access/qhttpthreaddelegate.cpp \ - access/qhttpmultipart.cpp \ access/qnetworkfile.cpp \ - access/qhttp2protocolhandler.cpp \ access/qhsts.cpp \ access/qhstspolicy.cpp \ access/qhstsstore.cpp @@ -94,4 +69,36 @@ qtConfig(networkdiskcache) { mac: LIBS_PRIVATE += -framework Security include($$PWD/../../3rdparty/zlib_dependency.pri) -include($$PWD/http2/http2.pri) + +qtConfig(http) { + include($$PWD/http2/http2.pri) + + SOURCES += \ + access/qabstractprotocolhandler.cpp \ + access/qhttp2protocolhandler.cpp \ + access/qhttpmultipart.cpp \ + access/qhttpnetworkconnection.cpp \ + access/qhttpnetworkconnectionchannel.cpp \ + access/qhttpnetworkheader.cpp \ + access/qhttpnetworkreply.cpp \ + access/qhttpnetworkrequest.cpp \ + access/qhttpprotocolhandler.cpp \ + access/qhttpthreaddelegate.cpp \ + access/qnetworkreplyhttpimpl.cpp \ + access/qspdyprotocolhandler.cpp + + HEADERS += \ + access/qabstractprotocolhandler_p.h \ + access/qhttp2protocolhandler_p.h \ + access/qhttpmultipart.h \ + access/qhttpmultipart_p.h \ + access/qhttpnetworkconnection_p.h \ + access/qhttpnetworkconnectionchannel_p.h \ + access/qhttpnetworkheader_p.h \ + access/qhttpnetworkreply_p.h \ + access/qhttpnetworkrequest_p.h \ + access/qhttpprotocolhandler_p.h \ + access/qhttpthreaddelegate_p.h \ + access/qnetworkreplyhttpimpl_p.h \ + access/qspdyprotocolhandler_p.h +} diff --git a/src/network/access/http2/hpack.cpp b/src/network/access/http2/hpack.cpp index 95e6f9051b..2d324d5092 100644 --- a/src/network/access/http2/hpack.cpp +++ b/src/network/access/http2/hpack.cpp @@ -67,18 +67,6 @@ HeaderSize header_size(const HttpHeader &header) struct BitPattern { - BitPattern() - : value(), - bitLength() - { - } - - BitPattern(uchar v, uchar len) - : value(v), - bitLength(len) - { - } - uchar value; uchar bitLength; }; @@ -102,11 +90,11 @@ using StreamError = BitIStream::Error; // It's always 1 or 0 actually, but the number of bits to extract // from the input stream - differs. -const BitPattern Indexed(1, 1); -const BitPattern LiteralIncrementalIndexing(1, 2); -const BitPattern LiteralNoIndexing(0, 4); -const BitPattern LiteralNeverIndexing(1, 4); -const BitPattern SizeUpdate(1, 3); +const BitPattern Indexed = {1, 1}; +const BitPattern LiteralIncrementalIndexing = {1, 2}; +const BitPattern LiteralNoIndexing = {0, 4}; +const BitPattern LiteralNeverIndexing = {1, 4}; +const BitPattern SizeUpdate = {1, 3}; bool is_literal_field(const BitPattern &pattern) { diff --git a/src/network/access/http2/http2streams_p.h b/src/network/access/http2/http2streams_p.h index 8465486ae8..0be6b3b253 100644 --- a/src/network/access/http2/http2streams_p.h +++ b/src/network/access/http2/http2streams_p.h @@ -62,6 +62,8 @@ #include <vector> +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE class QNonContiguousByteDevice; diff --git a/src/network/access/http2/huffman_p.h b/src/network/access/http2/huffman_p.h index 7195661664..c5324d42b1 100644 --- a/src/network/access/http2/huffman_p.h +++ b/src/network/access/http2/huffman_p.h @@ -62,19 +62,6 @@ namespace HPack struct CodeEntry { - CodeEntry() : byteValue(), - huffmanCode(), - bitLength() - { - } - - CodeEntry(quint32 val, quint32 code, quint32 len) - : byteValue(val), - huffmanCode(code), - bitLength(len) - { - } - quint32 byteValue; quint32 huffmanCode; quint32 bitLength; diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h index 33b0bc4ce3..678bae2d6e 100644 --- a/src/network/access/qabstractnetworkcache.h +++ b/src/network/access/qabstractnetworkcache.h @@ -131,7 +131,7 @@ public Q_SLOTS: virtual void clear() = 0; protected: - explicit QAbstractNetworkCache(QObject *parent = Q_NULLPTR); + explicit QAbstractNetworkCache(QObject *parent = nullptr); QAbstractNetworkCache(QAbstractNetworkCachePrivate &dd, QObject *parent); private: diff --git a/src/network/access/qabstractprotocolhandler.cpp b/src/network/access/qabstractprotocolhandler.cpp index d408f3b37a..f15dfe6899 100644 --- a/src/network/access/qabstractprotocolhandler.cpp +++ b/src/network/access/qabstractprotocolhandler.cpp @@ -40,8 +40,6 @@ #include <private/qabstractprotocolhandler_p.h> #include <private/qhttpnetworkconnectionchannel_p.h> -#ifndef QT_NO_HTTP - QT_BEGIN_NAMESPACE QAbstractProtocolHandler::QAbstractProtocolHandler(QHttpNetworkConnectionChannel *channel) @@ -62,5 +60,3 @@ void QAbstractProtocolHandler::setReply(QHttpNetworkReply *reply) } QT_END_NAMESPACE - -#endif // QT_NO_HTTP diff --git a/src/network/access/qabstractprotocolhandler_p.h b/src/network/access/qabstractprotocolhandler_p.h index 30814d6737..04a07734dd 100644 --- a/src/network/access/qabstractprotocolhandler_p.h +++ b/src/network/access/qabstractprotocolhandler_p.h @@ -53,7 +53,7 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> -#ifndef QT_NO_HTTP +QT_REQUIRE_CONFIG(http); QT_BEGIN_NAMESPACE @@ -81,6 +81,4 @@ protected: QT_END_NAMESPACE -#endif // QT_NO_HTTP - #endif // QABSTRACTPROTOCOLHANDLER_H diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp index 6a731afc2f..43a8a3663e 100644 --- a/src/network/access/qhsts.cpp +++ b/src/network/access/qhsts.cpp @@ -136,7 +136,7 @@ void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires, return; } - knownHosts.insert(pos, hostName, newPolicy); + knownHosts.insert(pos, {hostName, newPolicy}); if (hstsStore) hstsStore->addToObserved(newPolicy); return; @@ -144,8 +144,8 @@ void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires, if (newPolicy.isExpired()) knownHosts.erase(pos); - else if (*pos != newPolicy) - *pos = std::move(newPolicy); + else if (pos->second != newPolicy) + pos->second = std::move(newPolicy); else return; @@ -185,13 +185,13 @@ bool QHstsCache::isKnownHost(const QUrl &url) const while (nameToTest.fragment.size()) { auto const pos = knownHosts.find(nameToTest); if (pos != knownHosts.end()) { - if (pos.value().isExpired()) { + if (pos->second.isExpired()) { knownHosts.erase(pos); if (hstsStore) { // Inform our store that this policy has expired. - hstsStore->addToObserved(pos.value()); + hstsStore->addToObserved(pos->second); } - } else if (!superDomainMatch || pos.value().includesSubDomains()) { + } else if (!superDomainMatch || pos->second.includesSubDomains()) { return true; } } @@ -215,9 +215,9 @@ void QHstsCache::clear() QVector<QHstsPolicy> QHstsCache::policies() const { QVector<QHstsPolicy> values; - values.reserve(knownHosts.size()); + values.reserve(int(knownHosts.size())); for (const auto &host : knownHosts) - values << host; + values << host.second; return values; } diff --git a/src/network/access/qhsts_p.h b/src/network/access/qhsts_p.h index 2feb73b446..bc8708341d 100644 --- a/src/network/access/qhsts_p.h +++ b/src/network/access/qhsts_p.h @@ -61,7 +61,8 @@ #include <QtCore/qglobal.h> #include <QtCore/qpair.h> #include <QtCore/qurl.h> -#include <QtCore/qmap.h> + +#include <map> QT_BEGIN_NAMESPACE @@ -117,7 +118,7 @@ private: QStringRef fragment; }; - mutable QMap<HostName, QHstsPolicy> knownHosts; + mutable std::map<HostName, QHstsPolicy> knownHosts; QHstsStore *hstsStore = nullptr; }; diff --git a/src/network/access/qhstspolicy.cpp b/src/network/access/qhstspolicy.cpp index ab4695480b..46c9c22510 100644 --- a/src/network/access/qhstspolicy.cpp +++ b/src/network/access/qhstspolicy.cpp @@ -103,9 +103,15 @@ QHstsPolicy::QHstsPolicy() : d(new QHstsPolicyPrivate) } /*! - Constructs QHstsPolicy with \a expiry (in UTC): - - \a host data is interpreted according to \a mode; - - \a flags selects options to apply to this policy. + \enum QHstsPolicy::PolicyFlag + + \value IncludeSubDomains Indicates whether a policy must include subdomains +*/ + +/*! + Constructs QHstsPolicy with \a expiry (in UTC); \a flags is a value indicating + whether this policy must also include subdomains, \a host data is interpreted + according to \a mode. \sa QUrl::setHost(), QUrl::ParsingMode, QHstsPolicy::PolicyFlag */ @@ -213,4 +219,10 @@ bool QHstsPolicy::isExpired() const return !d->expiry.isValid() || d->expiry <= QDateTime::currentDateTimeUtc(); } +/*! + \fn void QHstsPolicy::swap(QHstsPolicy &other) + + Swaps this policy with the \a other policy. +*/ + QT_END_NAMESPACE diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 42f1343c52..0cdcee6b59 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -40,8 +40,6 @@ #include "qhttpnetworkconnection_p.h" #include "qhttp2protocolhandler_p.h" -#if !defined(QT_NO_HTTP) - #include "http2/bitstreams_p.h" #include <private/qnoncontiguousbytedevice_p.h> @@ -88,7 +86,8 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH if (size.second > maxHeaderListSize) return HttpHeader(); // Bad, we cannot send this request ... - for (const auto &field : request.header()) { + const auto requestHeader = request.header(); + for (const auto &field : requestHeader) { const HeaderSize delta = entry_size(field.first, field.second); if (!delta.first) // Overflow??? break; @@ -1511,5 +1510,3 @@ void QHttp2ProtocolHandler::closeSession() } QT_END_NAMESPACE - -#endif // !defined(QT_NO_HTTP) diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index dd209bd0ef..9165808302 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -55,8 +55,6 @@ #include <private/qabstractprotocolhandler_p.h> #include <private/qhttpnetworkrequest_p.h> -#if !defined(QT_NO_HTTP) - #include <private/http2protocol_p.h> #include <private/http2streams_p.h> #include <private/http2frames_p.h> @@ -75,6 +73,8 @@ #include <deque> #include <set> +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE class QHttp2ProtocolHandler : public QObject, public QAbstractProtocolHandler @@ -228,6 +228,4 @@ private: QT_END_NAMESPACE -#endif // !defined(QT_NO_HTTP) - #endif diff --git a/src/network/access/qhttpmultipart.h b/src/network/access/qhttpmultipart.h index 6d4531b099..78585a704d 100644 --- a/src/network/access/qhttpmultipart.h +++ b/src/network/access/qhttpmultipart.h @@ -46,6 +46,8 @@ #include <QtCore/QIODevice> #include <QtNetwork/QNetworkRequest> +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE @@ -98,8 +100,8 @@ public: AlternativeType }; - explicit QHttpMultiPart(QObject *parent = Q_NULLPTR); - explicit QHttpMultiPart(ContentType contentType, QObject *parent = Q_NULLPTR); + explicit QHttpMultiPart(QObject *parent = nullptr); + explicit QHttpMultiPart(ContentType contentType, QObject *parent = nullptr); ~QHttpMultiPart(); void append(const QHttpPart &httpPart); diff --git a/src/network/access/qhttpmultipart_p.h b/src/network/access/qhttpmultipart_p.h index a03df9cb13..363e0b346c 100644 --- a/src/network/access/qhttpmultipart_p.h +++ b/src/network/access/qhttpmultipart_p.h @@ -56,6 +56,8 @@ #include "qnetworkrequest_p.h" // for deriving QHttpPartPrivate from QNetworkHeadersPrivate #include "private/qobject_p.h" +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE @@ -124,30 +126,30 @@ public: ~QHttpMultiPartIODevice() { } - virtual bool atEnd() const Q_DECL_OVERRIDE { + virtual bool atEnd() const override { return readPointer == size(); } - virtual qint64 bytesAvailable() const Q_DECL_OVERRIDE { + virtual qint64 bytesAvailable() const override { return size() - readPointer; } - virtual void close() Q_DECL_OVERRIDE { + virtual void close() override { readPointer = 0; partOffsets.clear(); deviceSize = -1; QIODevice::close(); } - virtual qint64 bytesToWrite() const Q_DECL_OVERRIDE { + virtual qint64 bytesToWrite() const override { return 0; } - virtual qint64 size() const Q_DECL_OVERRIDE; - virtual bool isSequential() const Q_DECL_OVERRIDE; - virtual bool reset() Q_DECL_OVERRIDE; - virtual qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE; - virtual qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE; + virtual qint64 size() const override; + virtual bool isSequential() const override; + virtual bool reset() override; + virtual qint64 readData(char *data, qint64 maxSize) override; + virtual qint64 writeData(const char *data, qint64 maxSize) override; QHttpMultiPartPrivate *multiPart; qint64 readPointer; diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 8fdcc91efc..d24927b922 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -53,8 +53,6 @@ #include <qpair.h> #include <qdebug.h> -#ifndef QT_NO_HTTP - #ifndef QT_NO_SSL # include <private/qsslsocket_p.h> # include <QtNetwork/qsslkey.h> @@ -83,10 +81,11 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host networkLayerState(Unknown), hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true) , activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2 + || type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct #ifndef QT_NO_SSL - || type == QHttpNetworkConnection::ConnectionTypeSPDY + || type == QHttpNetworkConnection::ConnectionTypeSPDY #endif - ? 1 : defaultHttpChannelCount) + ? 1 : defaultHttpChannelCount) , channelCount(defaultHttpChannelCount) #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) @@ -122,7 +121,7 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() { for (int i = 0; i < channelCount; ++i) { if (channels[i].socket) { - QObject::disconnect(channels[i].socket, Q_NULLPTR, &channels[i], Q_NULLPTR); + QObject::disconnect(channels[i].socket, nullptr, &channels[i], nullptr); channels[i].socket->close(); delete channels[i].socket; } @@ -1065,6 +1064,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() } break; } + case QHttpNetworkConnection::ConnectionTypeHTTP2Direct: case QHttpNetworkConnection::ConnectionTypeHTTP2: case QHttpNetworkConnection::ConnectionTypeSPDY: { if (channels[0].spdyRequestsToSend.isEmpty() && channels[0].switchedToHttp2) @@ -1554,5 +1554,3 @@ void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpN QT_END_NAMESPACE #include "moc_qhttpnetworkconnection_p.cpp" - -#endif // QT_NO_HTTP diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index d3450417aa..91827a6eb1 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -71,7 +71,7 @@ #include <private/qhttpnetworkconnectionchannel_p.h> -#ifndef QT_NO_HTTP +QT_REQUIRE_CONFIG(http); QT_BEGIN_NAMESPACE @@ -94,7 +94,8 @@ public: enum ConnectionType { ConnectionTypeHTTP, ConnectionTypeSPDY, - ConnectionTypeHTTP2 + ConnectionTypeHTTP2, + ConnectionTypeHTTP2Direct }; #ifndef QT_NO_BEARERMANAGEMENT @@ -295,6 +296,4 @@ public: QT_END_NAMESPACE -#endif // QT_NO_HTTP - #endif diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 094a48a603..0ac14c78f6 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -45,8 +45,6 @@ #include <qpair.h> #include <qdebug.h> -#ifndef QT_NO_HTTP - #include <private/qhttp2protocolhandler_p.h> #include <private/qhttpprotocolhandler_p.h> #include <private/qspdyprotocolhandler_p.h> @@ -438,6 +436,10 @@ void QHttpNetworkConnectionChannel::allDone() return; } + // For clear text HTTP/2 we tried to upgrade from HTTP/1.1 to HTTP/2; for + // ConnectionTypeHTTP2Direct we can never be here in case of failure + // (after an attempt to read HTTP/1.1 as HTTP/2 frames) or we have a normal + // HTTP/2 response and thus can skip this test: if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 && !ssl && !switchedToHttp2) { if (Http2::is_protocol_upgraded(*reply)) { @@ -891,6 +893,14 @@ void QHttpNetworkConnectionChannel::_q_connected() connection->setSslContext(socketSslContext); } #endif + } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { + state = QHttpNetworkConnectionChannel::IdleState; + protocolHandler.reset(new QHttp2ProtocolHandler(this)); + if (spdyRequestsToSend.count() > 0) { + // In case our peer has sent us its settings (window size, max concurrent streams etc.) + // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection). + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); + } } else { state = QHttpNetworkConnectionChannel::IdleState; const bool tryProtocolUpgrade = connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2; @@ -1125,7 +1135,10 @@ void QHttpNetworkConnectionChannel::_q_encrypted() QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket); Q_ASSERT(sslSocket); - if (!protocolHandler) { + if (!protocolHandler && connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { + // ConnectionTypeHTTP2Direct does not rely on ALPN/NPN to negotiate HTTP/2, + // after establishing a secure connection we immediately start sending + // HTTP/2 frames. switch (sslSocket->sslConfiguration().nextProtocolNegotiationStatus()) { case QSslConfiguration::NextProtocolNegotiationNegotiated: case QSslConfiguration::NextProtocolNegotiationUnsupported: { @@ -1191,7 +1204,8 @@ void QHttpNetworkConnectionChannel::_q_encrypted() emitFinishedWithError(QNetworkReply::SslHandshakeFailedError, "detected unknown Next Protocol Negotiation protocol"); } - } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) { + } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { // We have to reset QHttp2ProtocolHandler's state machine, it's a new // connection and the handler's state is unique per connection. protocolHandler.reset(new QHttp2ProtocolHandler(this)); @@ -1203,10 +1217,12 @@ void QHttpNetworkConnectionChannel::_q_encrypted() pendingEncrypt = false; if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY || - connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) { + connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 || + connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { // we call setSpdyWasUsed(true) on the replies in the SPDY handler when the request is sent if (spdyRequestsToSend.count() > 0) { - // wait for data from the server first (e.g. initial window, max concurrent requests) + // In case our peer has sent us its settings (window size, max concurrent streams etc.) + // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection). QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } } else { // HTTP @@ -1303,5 +1319,3 @@ void QHttpNetworkConnectionChannel::setConnection(QHttpNetworkConnection *c) QT_END_NAMESPACE #include "moc_qhttpnetworkconnectionchannel_p.cpp" - -#endif // QT_NO_HTTP diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 844a7d5d15..e9cdae5653 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -68,8 +68,6 @@ #include <private/qhttpnetworkconnection_p.h> #include <private/qabstractprotocolhandler_p.h> -#ifndef QT_NO_HTTP - #ifndef QT_NO_SSL # include <QtNetwork/qsslsocket.h> # include <QtNetwork/qsslerror.h> @@ -80,6 +78,8 @@ #include <QtCore/qscopedpointer.h> +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE class QHttpNetworkRequest; @@ -216,6 +216,4 @@ public: QT_END_NAMESPACE -#endif // QT_NO_HTTP - #endif diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp index 7199abbf17..19a3dfcfe8 100644 --- a/src/network/access/qhttpnetworkheader.cpp +++ b/src/network/access/qhttpnetworkheader.cpp @@ -41,8 +41,6 @@ #include <algorithm> -#ifndef QT_NO_HTTP - QT_BEGIN_NAMESPACE QHttpNetworkHeaderPrivate::QHttpNetworkHeaderPrivate(const QUrl &newUrl) @@ -121,5 +119,3 @@ bool QHttpNetworkHeaderPrivate::operator==(const QHttpNetworkHeaderPrivate &othe QT_END_NAMESPACE - -#endif diff --git a/src/network/access/qhttpnetworkheader_p.h b/src/network/access/qhttpnetworkheader_p.h index 46aec1dd8c..f46c259919 100644 --- a/src/network/access/qhttpnetworkheader_p.h +++ b/src/network/access/qhttpnetworkheader_p.h @@ -53,11 +53,11 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> -#ifndef QT_NO_HTTP - #include <qshareddata.h> #include <qurl.h> +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE class Q_AUTOTEST_EXPORT QHttpNetworkHeader @@ -99,10 +99,6 @@ public: QT_END_NAMESPACE - -#endif // QT_NO_HTTP - - #endif // QHTTPNETWORKHEADER_H diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 778ba821e8..a657346958 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -40,8 +40,6 @@ #include "qhttpnetworkreply_p.h" #include "qhttpnetworkconnection_p.h" -#ifndef QT_NO_HTTP - #ifndef QT_NO_SSL # include <QtNetwork/qsslkey.h> # include <QtNetwork/qsslcipher.h> @@ -1035,5 +1033,3 @@ void QHttpNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) QT_END_NAMESPACE - -#endif // QT_NO_HTTP diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index faab03f056..863e21ea3e 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -53,8 +53,6 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> -#ifndef QT_NO_HTTP - #include <qplatformdefs.h> #ifndef QT_NO_COMPRESS @@ -77,6 +75,8 @@ struct z_stream_s; #include <private/qringbuffer_p.h> #include <private/qbytedata_p.h> +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE class QHttpNetworkConnection; @@ -92,18 +92,18 @@ public: explicit QHttpNetworkReply(const QUrl &url = QUrl(), QObject *parent = 0); virtual ~QHttpNetworkReply(); - QUrl url() const Q_DECL_OVERRIDE; - void setUrl(const QUrl &url) Q_DECL_OVERRIDE; + QUrl url() const override; + void setUrl(const QUrl &url) override; - int majorVersion() const Q_DECL_OVERRIDE; - int minorVersion() const Q_DECL_OVERRIDE; + int majorVersion() const override; + int minorVersion() const override; - qint64 contentLength() const Q_DECL_OVERRIDE; - void setContentLength(qint64 length) Q_DECL_OVERRIDE; + qint64 contentLength() const override; + void setContentLength(qint64 length) override; - QList<QPair<QByteArray, QByteArray> > header() const Q_DECL_OVERRIDE; - QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const Q_DECL_OVERRIDE; - void setHeaderField(const QByteArray &name, const QByteArray &data) Q_DECL_OVERRIDE; + QList<QPair<QByteArray, QByteArray> > header() const override; + QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const override; + void setHeaderField(const QByteArray &name, const QByteArray &data) override; void parseHeader(const QByteArray &header); // mainly for testing QHttpNetworkRequest request() const; @@ -285,7 +285,4 @@ public: QT_END_NAMESPACE -#endif // QT_NO_HTTP - - #endif // QHTTPNETWORKREPLY_H diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 60b566299f..3fcf946945 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -40,15 +40,13 @@ #include "qhttpnetworkrequest_p.h" #include "private/qnoncontiguousbytedevice_p.h" -#ifndef QT_NO_HTTP - QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, QHttpNetworkRequest::Priority pri, const QUrl &newUrl) : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0), autoDecompress(false), pipeliningAllowed(false), spdyAllowed(false), http2Allowed(false), - withCredentials(true), preConnect(false), redirectCount(0), + http2Direct(false), withCredentials(true), preConnect(false), redirectCount(0), redirectPolicy(QNetworkRequest::ManualRedirectPolicy) { } @@ -63,6 +61,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest pipeliningAllowed(other.pipeliningAllowed), spdyAllowed(other.spdyAllowed), http2Allowed(other.http2Allowed), + http2Direct(other.http2Direct), withCredentials(other.withCredentials), ssl(other.ssl), preConnect(other.preConnect), @@ -85,6 +84,7 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot && (pipeliningAllowed == other.pipeliningAllowed) && (spdyAllowed == other.spdyAllowed) && (http2Allowed == other.http2Allowed) + && (http2Direct == other.http2Direct) // we do not clear the customVerb in setOperation && (operation != QHttpNetworkRequest::Custom || (customVerb == other.customVerb)) && (withCredentials == other.withCredentials) @@ -350,6 +350,16 @@ void QHttpNetworkRequest::setHTTP2Allowed(bool b) d->http2Allowed = b; } +bool QHttpNetworkRequest::isHTTP2Direct() const +{ + return d->http2Direct; +} + +void QHttpNetworkRequest::setHTTP2Direct(bool b) +{ + d->http2Direct = b; +} + bool QHttpNetworkRequest::withCredentials() const { return d->withCredentials; @@ -383,5 +393,3 @@ int QHttpNetworkRequest::minorVersion() const QT_END_NAMESPACE -#endif - diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index ecf8856ded..2cbb8e255e 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -52,12 +52,12 @@ // #include <QtNetwork/private/qtnetworkglobal_p.h> -#ifndef QT_NO_HTTP - #include <private/qhttpnetworkheader_p.h> #include <QtNetwork/qnetworkrequest.h> #include <qmetatype.h> +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE class QNonContiguousByteDevice; @@ -90,18 +90,18 @@ public: QHttpNetworkRequest &operator=(const QHttpNetworkRequest &other); bool operator==(const QHttpNetworkRequest &other) const; - QUrl url() const Q_DECL_OVERRIDE; - void setUrl(const QUrl &url) Q_DECL_OVERRIDE; + QUrl url() const override; + void setUrl(const QUrl &url) override; - int majorVersion() const Q_DECL_OVERRIDE; - int minorVersion() const Q_DECL_OVERRIDE; + int majorVersion() const override; + int minorVersion() const override; - qint64 contentLength() const Q_DECL_OVERRIDE; - void setContentLength(qint64 length) Q_DECL_OVERRIDE; + qint64 contentLength() const override; + void setContentLength(qint64 length) override; - QList<QPair<QByteArray, QByteArray> > header() const Q_DECL_OVERRIDE; - QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const Q_DECL_OVERRIDE; - void setHeaderField(const QByteArray &name, const QByteArray &data) Q_DECL_OVERRIDE; + QList<QPair<QByteArray, QByteArray> > header() const override; + QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const override; + void setHeaderField(const QByteArray &name, const QByteArray &data) override; Operation operation() const; void setOperation(Operation operation); @@ -121,6 +121,9 @@ public: bool isHTTP2Allowed() const; void setHTTP2Allowed(bool b); + bool isHTTP2Direct() const; + void setHTTP2Direct(bool b); + bool withCredentials() const; void setWithCredentials(bool b); @@ -172,6 +175,7 @@ public: bool pipeliningAllowed; bool spdyAllowed; bool http2Allowed; + bool http2Direct; bool withCredentials; bool ssl; bool preConnect; @@ -184,7 +188,4 @@ QT_END_NAMESPACE Q_DECLARE_METATYPE(QHttpNetworkRequest) -#endif // QT_NO_HTTP - - #endif // QHTTPNETWORKREQUEST_H diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp index 37e8b9bed8..edcbdcbe0e 100644 --- a/src/network/access/qhttpprotocolhandler.cpp +++ b/src/network/access/qhttpprotocolhandler.cpp @@ -42,8 +42,6 @@ #include <private/qnoncontiguousbytedevice_p.h> #include <private/qhttpnetworkconnectionchannel_p.h> -#ifndef QT_NO_HTTP - QT_BEGIN_NAMESPACE QHttpProtocolHandler::QHttpProtocolHandler(QHttpNetworkConnectionChannel *channel) @@ -437,5 +435,3 @@ bool QHttpProtocolHandler::sendRequest() } QT_END_NAMESPACE - -#endif // QT_NO_HTTP diff --git a/src/network/access/qhttpprotocolhandler_p.h b/src/network/access/qhttpprotocolhandler_p.h index 863b988be3..8e766604bb 100644 --- a/src/network/access/qhttpprotocolhandler_p.h +++ b/src/network/access/qhttpprotocolhandler_p.h @@ -55,7 +55,7 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> #include <private/qabstractprotocolhandler_p.h> -#ifndef QT_NO_HTTP +QT_REQUIRE_CONFIG(http); QT_BEGIN_NAMESPACE @@ -64,13 +64,11 @@ public: QHttpProtocolHandler(QHttpNetworkConnectionChannel *channel); private: - virtual void _q_receiveReply() Q_DECL_OVERRIDE; - virtual void _q_readyRead() Q_DECL_OVERRIDE; - virtual bool sendRequest() Q_DECL_OVERRIDE; + virtual void _q_receiveReply() override; + virtual void _q_readyRead() override; + virtual bool sendRequest() override; }; QT_END_NAMESPACE -#endif // QT_NO_HTTP - #endif diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 3204f8da33..0e97acdd9d 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -50,8 +50,6 @@ #include "private/qnetworkaccesscache_p.h" #include "private/qnoncontiguousbytedevice_p.h" -#ifndef QT_NO_HTTP - QT_BEGIN_NAMESPACE static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url) @@ -197,7 +195,7 @@ public: setShareable(true); } - virtual void dispose() Q_DECL_OVERRIDE + virtual void dispose() override { #if 0 // sample code; do this right with the API Q_ASSERT(!isWorking()); @@ -292,11 +290,17 @@ void QHttpThreadDelegate::startRequest() QHttpNetworkConnection::ConnectionType connectionType = httpRequest.isHTTP2Allowed() ? QHttpNetworkConnection::ConnectionTypeHTTP2 : QHttpNetworkConnection::ConnectionTypeHTTP; + if (httpRequest.isHTTP2Direct()) { + Q_ASSERT(!httpRequest.isHTTP2Allowed()); + connectionType = QHttpNetworkConnection::ConnectionTypeHTTP2Direct; + } + #ifndef QT_NO_SSL if (ssl && !incomingSslConfiguration.data()) incomingSslConfiguration.reset(new QSslConfiguration); if (httpRequest.isHTTP2Allowed() && ssl) { + // With HTTP2Direct we do not try any protocol negotiation. QList<QByteArray> protocols; protocols << QSslConfiguration::ALPNProtocolHTTP2 << QSslConfiguration::NextProtocolHttp1_1; @@ -762,6 +766,4 @@ void QHttpThreadDelegate::synchronousProxyAuthenticationRequiredSlot(const QNet #endif -#endif // QT_NO_HTTP - QT_END_NAMESPACE diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index da115d6710..019a8b8b74 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -68,7 +68,7 @@ #include "qnetworkaccessauthenticationmanager_p.h" #include <QtNetwork/private/http2protocol_p.h> -#ifndef QT_NO_HTTP +QT_REQUIRE_CONFIG(http); QT_BEGIN_NAMESPACE @@ -218,12 +218,12 @@ public: { } - qint64 pos() const Q_DECL_OVERRIDE + qint64 pos() const override { return m_pos; } - const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE + const char* readPointer(qint64 maximumLength, qint64 &len) override { if (m_amount > 0) { len = m_amount; @@ -243,7 +243,7 @@ public: return 0; } - bool advanceReadPointer(qint64 a) Q_DECL_OVERRIDE + bool advanceReadPointer(qint64 a) override { if (m_data == 0) return false; @@ -258,7 +258,7 @@ public: return true; } - bool atEnd() const Q_DECL_OVERRIDE + bool atEnd() const override { if (m_amount > 0) return false; @@ -266,7 +266,7 @@ public: return m_atEnd; } - bool reset() Q_DECL_OVERRIDE + bool reset() override { m_amount = 0; m_data = 0; @@ -288,7 +288,7 @@ public: return b; } - qint64 size() const Q_DECL_OVERRIDE + qint64 size() const override { return m_size; } @@ -327,6 +327,4 @@ signals: QT_END_NAMESPACE -#endif // QT_NO_HTTP - #endif // QHTTPTHREADDELEGATE_H diff --git a/src/network/access/qnetworkaccessauthenticationmanager.cpp b/src/network/access/qnetworkaccessauthenticationmanager.cpp index 2b07833cda..b661cc45b3 100644 --- a/src/network/access/qnetworkaccessauthenticationmanager.cpp +++ b/src/network/access/qnetworkaccessauthenticationmanager.cpp @@ -95,7 +95,7 @@ public: } } - virtual void dispose() Q_DECL_OVERRIDE { delete this; } + virtual void dispose() override { delete this; } }; #ifndef QT_NO_NETWORKPROXY diff --git a/src/network/access/qnetworkaccesscache_p.h b/src/network/access/qnetworkaccesscache_p.h index 3732b5cbb4..69ea649a8a 100644 --- a/src/network/access/qnetworkaccesscache_p.h +++ b/src/network/access/qnetworkaccesscache_p.h @@ -106,7 +106,7 @@ signals: void entryReady(QNetworkAccessCache::CacheableObject *); protected: - void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *) override; private: // idea copied from qcache.h diff --git a/src/network/access/qnetworkaccesscachebackend_p.h b/src/network/access/qnetworkaccesscachebackend_p.h index 8db1a6b1d5..dfb0ce84d9 100644 --- a/src/network/access/qnetworkaccesscachebackend_p.h +++ b/src/network/access/qnetworkaccesscachebackend_p.h @@ -65,12 +65,12 @@ public: QNetworkAccessCacheBackend(); ~QNetworkAccessCacheBackend(); - void open() Q_DECL_OVERRIDE; - void closeDownstreamChannel() Q_DECL_OVERRIDE; + void open() override; + void closeDownstreamChannel() override; void closeUpstreamChannel(); void upstreamReadyRead(); - void downstreamReadyWrite() Q_DECL_OVERRIDE; + void downstreamReadyWrite() override; private: bool sendCacheContents(); diff --git a/src/network/access/qnetworkaccessdebugpipebackend_p.h b/src/network/access/qnetworkaccessdebugpipebackend_p.h index 1d1af61dbd..d9a7aabdad 100644 --- a/src/network/access/qnetworkaccessdebugpipebackend_p.h +++ b/src/network/access/qnetworkaccessdebugpipebackend_p.h @@ -68,10 +68,10 @@ public: QNetworkAccessDebugPipeBackend(); virtual ~QNetworkAccessDebugPipeBackend(); - virtual void open() Q_DECL_OVERRIDE; - virtual void closeDownstreamChannel() Q_DECL_OVERRIDE; + virtual void open() override; + virtual void closeDownstreamChannel() override; - virtual void downstreamReadyWrite() Q_DECL_OVERRIDE; + virtual void downstreamReadyWrite() override; protected: void pushFromSocketToDownstream(); @@ -101,9 +101,9 @@ private: class QNetworkAccessDebugPipeBackendFactory: public QNetworkAccessBackendFactory { public: - virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; + virtual QStringList supportedSchemes() const override; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, - const QNetworkRequest &request) const Q_DECL_OVERRIDE; + const QNetworkRequest &request) const override; }; #endif // QT_BUILD_INTERNAL diff --git a/src/network/access/qnetworkaccessfilebackend_p.h b/src/network/access/qnetworkaccessfilebackend_p.h index 081ff2b9e7..2c01fb1121 100644 --- a/src/network/access/qnetworkaccessfilebackend_p.h +++ b/src/network/access/qnetworkaccessfilebackend_p.h @@ -66,10 +66,10 @@ public: QNetworkAccessFileBackend(); virtual ~QNetworkAccessFileBackend(); - virtual void open() Q_DECL_OVERRIDE; - virtual void closeDownstreamChannel() Q_DECL_OVERRIDE; + virtual void open() override; + virtual void closeDownstreamChannel() override; - virtual void downstreamReadyWrite() Q_DECL_OVERRIDE; + virtual void downstreamReadyWrite() override; public slots: void uploadReadyReadSlot(); @@ -87,9 +87,9 @@ private: class QNetworkAccessFileBackendFactory: public QNetworkAccessBackendFactory { public: - virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; + virtual QStringList supportedSchemes() const override; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, - const QNetworkRequest &request) const Q_DECL_OVERRIDE; + const QNetworkRequest &request) const override; }; QT_END_NAMESPACE diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index 0df2569e87..c5404e4221 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -94,7 +94,7 @@ public: setShareable(false); } - void dispose() Q_DECL_OVERRIDE + void dispose() override { connect(this, SIGNAL(done(bool)), this, SLOT(deleteLater())); close(); diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h index 0f26d05327..4bd082fb67 100644 --- a/src/network/access/qnetworkaccessftpbackend_p.h +++ b/src/network/access/qnetworkaccessftpbackend_p.h @@ -84,10 +84,10 @@ public: QNetworkAccessFtpBackend(); virtual ~QNetworkAccessFtpBackend(); - virtual void open() Q_DECL_OVERRIDE; - virtual void closeDownstreamChannel() Q_DECL_OVERRIDE; + virtual void open() override; + virtual void closeDownstreamChannel() override; - virtual void downstreamReadyWrite() Q_DECL_OVERRIDE; + virtual void downstreamReadyWrite() override; enum CacheCleanupMode { ReleaseCachedConnection, @@ -115,9 +115,9 @@ private: class QNetworkAccessFtpBackendFactory: public QNetworkAccessBackendFactory { public: - virtual QStringList supportedSchemes() const Q_DECL_OVERRIDE; + virtual QStringList supportedSchemes() const override; virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op, - const QNetworkRequest &request) const Q_DECL_OVERRIDE; + const QNetworkRequest &request) const override; }; QT_END_NAMESPACE diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index d5a0261f43..07644b869f 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -66,10 +66,12 @@ #include "QtNetwork/private/qauthenticator_p.h" #include "QtNetwork/qsslconfiguration.h" #include "QtNetwork/qnetworkconfigmanager.h" -#include "QtNetwork/qhttpmultipart.h" -#include "qhttpmultipart_p.h" +#if QT_CONFIG(http) +#include "qhttpmultipart.h" +#include "qhttpmultipart_p.h" #include "qnetworkreplyhttpimpl_p.h" +#endif #include "qthread.h" @@ -469,7 +471,7 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) qRegisterMetaType<QSslPreSharedKeyAuthenticator *>(); #endif qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >(); -#ifndef QT_NO_HTTP +#if QT_CONFIG(http) qRegisterMetaType<QHttpNetworkRequest>(); #endif qRegisterMetaType<QNetworkReply::NetworkError>(); @@ -779,7 +781,9 @@ bool QNetworkAccessManager::isStrictTransportSecurityStoreEnabled() const /*! \since 5.9 - Adds HTTP Strict Transport Security policies contained in \a knownHosts into HSTS cache. + Adds HTTP Strict Transport Security policies into HSTS cache. + \a knownHosts contains the known hosts that have QHstsPolicy + information. \note An expired policy will remove a known host from the cache, if previously present. @@ -877,6 +881,7 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const return reply; } +#if QT_CONFIG(http) /*! \since 4.8 @@ -916,6 +921,7 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QHttpM QNetworkReply *reply = put(newRequest, device); return reply; } +#endif // QT_CONFIG(http) /*! Uploads the contents of \a data to the destination \a request and @@ -1283,6 +1289,7 @@ QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &r return reply; } +#if QT_CONFIG(http) /*! \since 5.8 @@ -1304,6 +1311,7 @@ QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &r QNetworkReply *reply = sendCustomRequest(newRequest, verb, device); return reply; } +#endif // QT_CONFIG(http) /*! Returns a new QNetworkReply object to handle the operation \a op @@ -1416,7 +1424,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera } } -#ifndef QT_NO_HTTP +#if QT_CONFIG(http) // Since Qt 5 we use the new QNetworkReplyHttpImpl if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http") #ifndef QT_NO_SSL @@ -1448,7 +1456,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera #endif return reply; } -#endif // QT_NO_HTTP +#endif // QT_CONFIG(http) // first step: create the reply QNetworkReplyImpl *reply = new QNetworkReplyImpl(this); @@ -1524,7 +1532,7 @@ QStringList QNetworkAccessManager::supportedSchemesImplementation() const QStringList schemes = d->backendSupportedSchemes(); // Those ones don't exist in backends -#ifndef QT_NO_HTTP +#if QT_CONFIG(http) schemes << QStringLiteral("http"); #ifndef QT_NO_SSL if (QSslSocket::supportsSsl()) @@ -1991,6 +1999,7 @@ void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::Sess #endif // QT_NO_BEARERMANAGEMENT +#if QT_CONFIG(http) QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart) { // copy the request, we probably need to add some headers @@ -2038,6 +2047,7 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq return newRequest; } +#endif // QT_CONFIG(http) QT_END_NAMESPACE diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 4806ec0475..a0ce3eddcd 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -100,7 +100,7 @@ public: Q_ENUM(NetworkAccessibility) #endif - explicit QNetworkAccessManager(QObject *parent = Q_NULLPTR); + explicit QNetworkAccessManager(QObject *parent = nullptr); ~QNetworkAccessManager(); // ### Qt 6: turn into virtual @@ -134,14 +134,17 @@ public: QNetworkReply *get(const QNetworkRequest &request); QNetworkReply *post(const QNetworkRequest &request, QIODevice *data); QNetworkReply *post(const QNetworkRequest &request, const QByteArray &data); - QNetworkReply *post(const QNetworkRequest &request, QHttpMultiPart *multiPart); QNetworkReply *put(const QNetworkRequest &request, QIODevice *data); QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data); - QNetworkReply *put(const QNetworkRequest &request, QHttpMultiPart *multiPart); QNetworkReply *deleteResource(const QNetworkRequest &request); - QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data = Q_NULLPTR); + QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data = nullptr); QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data); + +#if QT_CONFIG(http) + QNetworkReply *post(const QNetworkRequest &request, QHttpMultiPart *multiPart); + QNetworkReply *put(const QNetworkRequest &request, QHttpMultiPart *multiPart); QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart); +#endif #ifndef QT_NO_BEARERMANAGEMENT void setConfiguration(const QNetworkConfiguration &config); @@ -181,7 +184,7 @@ Q_SIGNALS: protected: virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, - QIODevice *outgoingData = Q_NULLPTR); + QIODevice *outgoingData = nullptr); protected Q_SLOTS: QStringList supportedSchemesImplementation() const; diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index e5257251a4..428110e8bc 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -164,7 +164,9 @@ public: #endif +#if QT_CONFIG(http) QNetworkRequest prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart); +#endif // this is the cache for storing downloaded files QAbstractNetworkCache *networkCache; diff --git a/src/network/access/qnetworkcookiejar.h b/src/network/access/qnetworkcookiejar.h index f9c1549e20..c3b2200443 100644 --- a/src/network/access/qnetworkcookiejar.h +++ b/src/network/access/qnetworkcookiejar.h @@ -54,7 +54,7 @@ class Q_NETWORK_EXPORT QNetworkCookieJar: public QObject { Q_OBJECT public: - explicit QNetworkCookieJar(QObject *parent = Q_NULLPTR); + explicit QNetworkCookieJar(QObject *parent = nullptr); virtual ~QNetworkCookieJar(); virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const; diff --git a/src/network/access/qnetworkdiskcache.h b/src/network/access/qnetworkdiskcache.h index 0e9258f6de..ff7d3192e8 100644 --- a/src/network/access/qnetworkdiskcache.h +++ b/src/network/access/qnetworkdiskcache.h @@ -53,7 +53,7 @@ class Q_NETWORK_EXPORT QNetworkDiskCache : public QAbstractNetworkCache Q_OBJECT public: - explicit QNetworkDiskCache(QObject *parent = Q_NULLPTR); + explicit QNetworkDiskCache(QObject *parent = nullptr); ~QNetworkDiskCache(); QString cacheDirectory() const; @@ -62,18 +62,18 @@ public: qint64 maximumCacheSize() const; void setMaximumCacheSize(qint64 size); - qint64 cacheSize() const Q_DECL_OVERRIDE; - QNetworkCacheMetaData metaData(const QUrl &url) Q_DECL_OVERRIDE; - void updateMetaData(const QNetworkCacheMetaData &metaData) Q_DECL_OVERRIDE; - QIODevice *data(const QUrl &url) Q_DECL_OVERRIDE; - bool remove(const QUrl &url) Q_DECL_OVERRIDE; - QIODevice *prepare(const QNetworkCacheMetaData &metaData) Q_DECL_OVERRIDE; - void insert(QIODevice *device) Q_DECL_OVERRIDE; + qint64 cacheSize() const override; + QNetworkCacheMetaData metaData(const QUrl &url) override; + void updateMetaData(const QNetworkCacheMetaData &metaData) override; + QIODevice *data(const QUrl &url) override; + bool remove(const QUrl &url) override; + QIODevice *prepare(const QNetworkCacheMetaData &metaData) override; + void insert(QIODevice *device) override; QNetworkCacheMetaData fileMetaData(const QString &fileName) const; public Q_SLOTS: - void clear() Q_DECL_OVERRIDE; + void clear() override; protected: virtual qint64 expire(); diff --git a/src/network/access/qnetworkfile_p.h b/src/network/access/qnetworkfile_p.h index dd56b24bd8..e788308d82 100644 --- a/src/network/access/qnetworkfile_p.h +++ b/src/network/access/qnetworkfile_p.h @@ -67,7 +67,7 @@ public: public Q_SLOTS: void open(); - void close() Q_DECL_OVERRIDE; + void close() override; Q_SIGNALS: void finished(bool ok); diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index d858e07d84..63c2752caf 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -114,8 +114,8 @@ public: ~QNetworkReply(); // reimplemented from QIODevice - virtual void close() Q_DECL_OVERRIDE; - virtual bool isSequential() const Q_DECL_OVERRIDE; + virtual void close() override; + virtual bool isSequential() const override; // like QAbstractSocket: qint64 readBufferSize() const; @@ -169,9 +169,9 @@ Q_SIGNALS: void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); protected: - explicit QNetworkReply(QObject *parent = Q_NULLPTR); + explicit QNetworkReply(QObject *parent = nullptr); QNetworkReply(QNetworkReplyPrivate &dd, QObject *parent); - virtual qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE; + virtual qint64 writeData(const char *data, qint64 len) override; void setOperation(QNetworkAccessManager::Operation operation); void setRequest(const QNetworkRequest &request); diff --git a/src/network/access/qnetworkreplydataimpl_p.h b/src/network/access/qnetworkreplydataimpl_p.h index c8b44d7539..81d2110d69 100644 --- a/src/network/access/qnetworkreplydataimpl_p.h +++ b/src/network/access/qnetworkreplydataimpl_p.h @@ -67,15 +67,15 @@ class QNetworkReplyDataImpl: public QNetworkReply public: QNetworkReplyDataImpl(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op); ~QNetworkReplyDataImpl(); - virtual void abort() Q_DECL_OVERRIDE; + virtual void abort() override; // reimplemented from QNetworkReply - virtual void close() Q_DECL_OVERRIDE; - virtual qint64 bytesAvailable() const Q_DECL_OVERRIDE; - virtual bool isSequential () const Q_DECL_OVERRIDE; - qint64 size() const Q_DECL_OVERRIDE; + virtual void close() override; + virtual qint64 bytesAvailable() const override; + virtual bool isSequential () const override; + qint64 size() const override; - virtual qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; + virtual qint64 readData(char *data, qint64 maxlen) override; Q_DECLARE_PRIVATE(QNetworkReplyDataImpl) }; diff --git a/src/network/access/qnetworkreplyfileimpl_p.h b/src/network/access/qnetworkreplyfileimpl_p.h index d6af66152e..55aece0bed 100644 --- a/src/network/access/qnetworkreplyfileimpl_p.h +++ b/src/network/access/qnetworkreplyfileimpl_p.h @@ -67,15 +67,15 @@ class QNetworkReplyFileImpl: public QNetworkReply public: QNetworkReplyFileImpl(QNetworkAccessManager *manager, const QNetworkRequest &req, const QNetworkAccessManager::Operation op); ~QNetworkReplyFileImpl(); - virtual void abort() Q_DECL_OVERRIDE; + virtual void abort() override; // reimplemented from QNetworkReply - virtual void close() Q_DECL_OVERRIDE; - virtual qint64 bytesAvailable() const Q_DECL_OVERRIDE; - virtual bool isSequential () const Q_DECL_OVERRIDE; - qint64 size() const Q_DECL_OVERRIDE; + virtual void close() override; + virtual qint64 bytesAvailable() const override; + virtual bool isSequential () const override; + qint64 size() const override; - virtual qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; + virtual qint64 readData(char *data, qint64 maxlen) override; private Q_SLOTS: void fileOpenFinished(bool isOpen); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 382da0db5a..96016453c2 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -60,8 +60,6 @@ #include "qnetworkcookiejar.h" -#ifndef QT_NO_HTTP - #include <string.h> // for strchr QT_BEGIN_NAMESPACE @@ -773,6 +771,12 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (request.attribute(QNetworkRequest::HTTP2AllowedAttribute).toBool()) httpRequest.setHTTP2Allowed(true); + if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) { + // Intentionally mutually exclusive - cannot be both direct and 'allowed' + httpRequest.setHTTP2Direct(true); + httpRequest.setHTTP2Allowed(false); + } + if (static_cast<QNetworkRequest::LoadControl> (newHttpRequest.attribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual) @@ -1288,7 +1292,9 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte q->setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu); const QVariant http2Allowed = request.attribute(QNetworkRequest::HTTP2AllowedAttribute); - if (http2Allowed.isValid() && http2Allowed.toBool()) { + const QVariant http2Direct = request.attribute(QNetworkRequest::Http2DirectAttribute); + if ((http2Allowed.isValid() && http2Allowed.toBool()) + || (http2Direct.isValid() && http2Direct.toBool())) { q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, spdyWasUsed); q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, false); } else { @@ -2375,5 +2381,3 @@ void QNetworkReplyHttpImplPrivate::completeCacheSave() } QT_END_NAMESPACE - -#endif // QT_NO_HTTP diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 9d47f65ce7..f5f01d0811 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -72,7 +72,7 @@ #include <QtNetwork/QSslConfiguration> #endif -#ifndef QT_NO_HTTP +QT_REQUIRE_CONFIG(http); QT_BEGIN_NAMESPACE @@ -86,14 +86,14 @@ public: QNetworkReplyHttpImpl(QNetworkAccessManager* const, const QNetworkRequest&, QNetworkAccessManager::Operation&, QIODevice* outgoingData); virtual ~QNetworkReplyHttpImpl(); - void close() Q_DECL_OVERRIDE; - void abort() Q_DECL_OVERRIDE; - qint64 bytesAvailable() const Q_DECL_OVERRIDE; - bool isSequential () const Q_DECL_OVERRIDE; - qint64 size() const Q_DECL_OVERRIDE; - qint64 readData(char*, qint64) Q_DECL_OVERRIDE; - void setReadBufferSize(qint64 size) Q_DECL_OVERRIDE; - bool canReadLine () const Q_DECL_OVERRIDE; + void close() override; + void abort() override; + qint64 bytesAvailable() const override; + bool isSequential () const override; + qint64 size() const override; + qint64 readData(char*, qint64) override; + void setReadBufferSize(qint64 size) override; + bool canReadLine () const override; Q_DECLARE_PRIVATE(QNetworkReplyHttpImpl) Q_PRIVATE_SLOT(d_func(), void _q_startOperation()) @@ -141,10 +141,10 @@ public: #ifndef QT_NO_SSL protected: - void ignoreSslErrors() Q_DECL_OVERRIDE; - void ignoreSslErrorsImplementation(const QList<QSslError> &errors) Q_DECL_OVERRIDE; - void setSslConfigurationImplementation(const QSslConfiguration &configuration) Q_DECL_OVERRIDE; - void sslConfigurationImplementation(QSslConfiguration &configuration) const Q_DECL_OVERRIDE; + void ignoreSslErrors() override; + void ignoreSslErrorsImplementation(const QList<QSslError> &errors) override; + void setSslConfigurationImplementation(const QSslConfiguration &configuration) override; + void sslConfigurationImplementation(QSslConfiguration &configuration) const override; #endif signals: @@ -315,6 +315,4 @@ public: QT_END_NAMESPACE -#endif // QT_NO_HTTP - #endif diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 7cd99392d3..f4e8284ab6 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -76,15 +76,15 @@ class QNetworkReplyImpl: public QNetworkReply public: QNetworkReplyImpl(QObject *parent = 0); ~QNetworkReplyImpl(); - virtual void abort() Q_DECL_OVERRIDE; + virtual void abort() override; // reimplemented from QNetworkReply / QIODevice - virtual void close() Q_DECL_OVERRIDE; - virtual qint64 bytesAvailable() const Q_DECL_OVERRIDE; - virtual void setReadBufferSize(qint64 size) Q_DECL_OVERRIDE; + virtual void close() override; + virtual qint64 bytesAvailable() const override; + virtual void setReadBufferSize(qint64 size) override; - virtual qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - virtual bool event(QEvent *) Q_DECL_OVERRIDE; + virtual qint64 readData(char *data, qint64 maxlen) override; + virtual bool event(QEvent *) override; Q_DECLARE_PRIVATE(QNetworkReplyImpl) Q_PRIVATE_SLOT(d_func(), void _q_startOperation()) @@ -101,10 +101,10 @@ public: #ifndef QT_NO_SSL protected: - void sslConfigurationImplementation(QSslConfiguration &configuration) const Q_DECL_OVERRIDE; - void setSslConfigurationImplementation(const QSslConfiguration &configuration) Q_DECL_OVERRIDE; - virtual void ignoreSslErrors() Q_DECL_OVERRIDE; - virtual void ignoreSslErrorsImplementation(const QList<QSslError> &errors) Q_DECL_OVERRIDE; + void sslConfigurationImplementation(QSslConfiguration &configuration) const override; + void setSslConfigurationImplementation(const QSslConfiguration &configuration) override; + virtual void ignoreSslErrors() override; + virtual void ignoreSslErrorsImplementation(const QList<QSslError> &errors) override; #endif }; @@ -219,9 +219,9 @@ public: QNetworkAccessManager::Operation op); ~QDisabledNetworkReply(); - void abort() Q_DECL_OVERRIDE { } + void abort() override { } protected: - qint64 readData(char *, qint64) Q_DECL_OVERRIDE { return -1; } + qint64 readData(char *, qint64) override { return -1; } }; #endif diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 60701d45be..99f72a7955 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -298,6 +298,20 @@ QT_BEGIN_NAMESPACE This attribute obsoletes FollowRedirectsAttribute. (This value was introduced in 5.9.) + \value Http2DirectAttribute + Requests only, type: QMetaType::Bool (default: false) + If set, this attribute will force QNetworkAccessManager to use + HTTP/2 protocol without initial HTTP/2 protocol negotiation. + Use of this attribute implies prior knowledge that a particular + server supports HTTP/2. The attribute works with SSL or 'cleartext' + HTTP/2. If a server turns out to not support HTTP/2, when HTTP/2 direct + was specified, QNetworkAccessManager gives up, without attempting to + fall back to HTTP/1.1. If both HTTP2AllowedAttribute and + Http2DirectAttribute are set, Http2DirectAttribute takes priority. + (This value was introduced in 5.10.) + + \omitvalue ResourceTypeAttribute + \value User Special type. Additional information can be passed in QVariants with types ranging from User to UserMax. The default diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 68d4ae6d6b..e104c139d9 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -92,6 +92,8 @@ public: HTTP2WasUsedAttribute, OriginalContentLengthAttribute, RedirectPolicyAttribute, + Http2DirectAttribute, + ResourceTypeAttribute, // internal User = 1000, UserMax = 32767 diff --git a/src/network/access/qspdyprotocolhandler.cpp b/src/network/access/qspdyprotocolhandler.cpp index 445a2a1c29..403c01e974 100644 --- a/src/network/access/qspdyprotocolhandler.cpp +++ b/src/network/access/qspdyprotocolhandler.cpp @@ -43,7 +43,7 @@ #include <private/qhttpnetworkconnectionchannel_p.h> #include <QtCore/QtEndian> -#if !defined(QT_NO_HTTP) && !defined(QT_NO_SSL) +#if !defined(QT_NO_SSL) QT_BEGIN_NAMESPACE @@ -1294,4 +1294,4 @@ qint32 QSpdyProtocolHandler::generateNextStreamID() QT_END_NAMESPACE -#endif // !defined(QT_NO_HTTP) && !defined(QT_NO_SSL) +#endif // !defined(QT_NO_SSL) diff --git a/src/network/access/qspdyprotocolhandler_p.h b/src/network/access/qspdyprotocolhandler_p.h index 0a18505b23..dd93a9aba2 100644 --- a/src/network/access/qspdyprotocolhandler_p.h +++ b/src/network/access/qspdyprotocolhandler_p.h @@ -58,7 +58,9 @@ #include <zlib.h> -#if !defined(QT_NO_HTTP) && !defined(QT_NO_SSL) +QT_REQUIRE_CONFIG(http); + +#if !defined(QT_NO_SSL) QT_BEGIN_NAMESPACE @@ -101,9 +103,9 @@ public: Q_DECLARE_FLAGS(SETTINGS_ID_Flags, SETTINGS_ID_Flag) - virtual void _q_receiveReply() Q_DECL_OVERRIDE; - virtual void _q_readyRead() Q_DECL_OVERRIDE; - virtual bool sendRequest() Q_DECL_OVERRIDE; + virtual void _q_receiveReply() override; + virtual void _q_readyRead() override; + virtual bool sendRequest() override; private slots: void _q_uploadDataReadyRead(); @@ -223,6 +225,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::SETTINGS_ID_Flags) QT_END_NAMESPACE -#endif // !defined(QT_NO_HTTP) && !defined(QT_NO_SSL) +#endif // !defined(QT_NO_SSL) #endif // QSPDYPROTOCOLHANDLER_H diff --git a/src/network/bearer/qnetworkconfigmanager.h b/src/network/bearer/qnetworkconfigmanager.h index da248bc7d0..e8866999c7 100644 --- a/src/network/bearer/qnetworkconfigmanager.h +++ b/src/network/bearer/qnetworkconfigmanager.h @@ -66,7 +66,7 @@ public: Q_DECLARE_FLAGS(Capabilities, Capability) - explicit QNetworkConfigurationManager(QObject *parent = Q_NULLPTR); + explicit QNetworkConfigurationManager(QObject *parent = nullptr); virtual ~QNetworkConfigurationManager(); QNetworkConfigurationManager::Capabilities capabilities() const; diff --git a/src/network/bearer/qnetworksession.h b/src/network/bearer/qnetworksession.h index d96b8915eb..1b5ae9098b 100644 --- a/src/network/bearer/qnetworksession.h +++ b/src/network/bearer/qnetworksession.h @@ -87,7 +87,7 @@ public: Q_DECLARE_FLAGS(UsagePolicies, UsagePolicy) - explicit QNetworkSession(const QNetworkConfiguration &connConfig, QObject *parent = Q_NULLPTR); + explicit QNetworkSession(const QNetworkConfiguration &connConfig, QObject *parent = nullptr); virtual ~QNetworkSession(); bool isOpen() const; @@ -131,8 +131,8 @@ Q_SIGNALS: void usagePoliciesChanged(QNetworkSession::UsagePolicies usagePolicies); protected: - virtual void connectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE; - virtual void disconnectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE; + virtual void connectNotify(const QMetaMethod &signal) override; + virtual void disconnectNotify(const QMetaMethod &signal) override; private: Q_DISABLE_COPY(QNetworkSession) diff --git a/src/network/configure.json b/src/network/configure.json index 770921f9a6..94a23bbc78 100644 --- a/src/network/configure.json +++ b/src/network/configure.json @@ -108,6 +108,24 @@ }, "use": "network" }, + "linux-netlink": { + "label": "Linux AF_NETLINK sockets", + "type": "compile", + "test": { + "include": [ "asm/types.h", "linux/netlink.h", "linux/rtnetlink.h", "sys/socket.h" ], + "main": [ + "struct rtattr rta = { };", + "struct ifinfomsg ifi = {};", + "struct ifaddrmsg ifa = {};", + "struct ifa_cacheinfo ci;", + "ci.ifa_prefered = ci.ifa_valid = 0;", + "(void)RTM_NEWLINK; (void)RTM_NEWADDR;", + "(void)IFLA_ADDRESS; (void)IFLA_IFNAME;", + "(void)IFA_ADDRESS; (void)IFA_LABEL; (void)IFA_CACHEINFO;", + "(void)(IFA_F_SECONDARY | IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_MANAGETEMPADDR);" + ] + } + }, "sctp": { "label": "SCTP support", "type": "compile", @@ -153,6 +171,11 @@ "condition": "libs.libproxy", "output": [ "privateFeature" ] }, + "linux-netlink": { + "label": "Linux AF_NETLINK", + "condition": "config.linux && tests.linux-netlink", + "output": [ "privateFeature" ] + }, "openssl": { "label": "OpenSSL", "enable": "input.openssl == 'yes' || input.openssl == 'linked' || input.openssl == 'runtime'", @@ -262,6 +285,12 @@ "section": "Networking", "condition": "features.temporaryfile", "output": [ "publicFeature", "feature" ] + }, + "dnslookup": { + "label": "QDnsLookup", + "purpose": "Provides API for DNS lookups.", + "section": "Networking", + "output": [ "publicFeature" ] } }, @@ -302,6 +331,11 @@ For example: "getifaddrs", "ipv6ifname", "libproxy", { "type": "feature", + "args": "linux-netlink", + "condition": "config.linux" + }, + { + "type": "feature", "args": "securetransport", "condition": "config.darwin" }, diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index b822a70e88..11b80d59d5 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -7,8 +7,6 @@ HEADERS += kernel/qtnetworkglobal.h \ kernel/qtnetworkglobal_p.h \ kernel/qauthenticator.h \ kernel/qauthenticator_p.h \ - kernel/qdnslookup.h \ - kernel/qdnslookup_p.h \ kernel/qhostaddress.h \ kernel/qhostaddress_p.h \ kernel/qhostinfo.h \ @@ -17,10 +15,10 @@ HEADERS += kernel/qtnetworkglobal.h \ kernel/qnetworkdatagram_p.h \ kernel/qnetworkinterface.h \ kernel/qnetworkinterface_p.h \ + kernel/qnetworkinterface_unix_p.h \ kernel/qnetworkproxy.h SOURCES += kernel/qauthenticator.cpp \ - kernel/qdnslookup.cpp \ kernel/qhostaddress.cpp \ kernel/qhostinfo.cpp \ kernel/qnetworkdatagram.cpp \ @@ -32,12 +30,22 @@ qtConfig(ftp) { SOURCES += kernel/qurlinfo.cpp } +qtConfig(dnslookup) { + HEADERS += kernel/qdnslookup.h \ + kernel/qdnslookup_p.h + + SOURCES += kernel/qdnslookup.cpp +} + unix { - !integrity: SOURCES += kernel/qdnslookup_unix.cpp - SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp + !integrity:qtConfig(dnslookup): SOURCES += kernel/qdnslookup_unix.cpp + SOURCES += kernel/qhostinfo_unix.cpp + + qtConfig(linux-netlink): SOURCES += kernel/qnetworkinterface_linux.cpp + else: SOURCES += kernel/qnetworkinterface_unix.cpp } -android { +android:qtConfig(dnslookup) { SOURCES -= kernel/qdnslookup_unix.cpp SOURCES += kernel/qdnslookup_android.cpp } @@ -46,12 +54,12 @@ win32: { SOURCES += kernel/qhostinfo_win.cpp !winrt { - SOURCES += kernel/qdnslookup_win.cpp \ - kernel/qnetworkinterface_win.cpp + SOURCES += kernel/qnetworkinterface_win.cpp + qtConfig(dnslookup): SOURCES += kernel/qdnslookup_win.cpp LIBS_PRIVATE += -ldnsapi -liphlpapi } else { - SOURCES += kernel/qdnslookup_winrt.cpp \ - kernel/qnetworkinterface_winrt.cpp + SOURCES += kernel/qnetworkinterface_winrt.cpp + qtConfig(dnslookup): SOURCES += kernel/qdnslookup_winrt.cpp } } @@ -60,6 +68,7 @@ mac { !uikit: LIBS_PRIVATE += -framework CoreServices -framework SystemConfiguration } +uikit:HEADERS += kernel/qnetworkinterface_uikit_p.h osx:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:!winrt: SOURCES += kernel/qnetworkproxy_win.cpp else: qtConfig(libproxy) { diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h index ead5e650f5..eebd0abe66 100644 --- a/src/network/kernel/qdnslookup.h +++ b/src/network/kernel/qdnslookup.h @@ -47,6 +47,8 @@ #include <QtCore/qsharedpointer.h> #include <QtCore/qstring.h> +QT_REQUIRE_CONFIG(dnslookup); + QT_BEGIN_NAMESPACE class QHostAddress; @@ -218,9 +220,9 @@ public: }; Q_ENUM(Type) - explicit QDnsLookup(QObject *parent = Q_NULLPTR); - QDnsLookup(Type type, const QString &name, QObject *parent = Q_NULLPTR); - QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent = Q_NULLPTR); + explicit QDnsLookup(QObject *parent = nullptr); + QDnsLookup(Type type, const QString &name, QObject *parent = nullptr); + QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent = nullptr); ~QDnsLookup(); Error error() const; diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h index d070286383..4584396efe 100644 --- a/src/network/kernel/qdnslookup_p.h +++ b/src/network/kernel/qdnslookup_p.h @@ -60,6 +60,8 @@ #include "QtNetwork/qhostaddress.h" #include "private/qobject_p.h" +QT_REQUIRE_CONFIG(dnslookup); + QT_BEGIN_NAMESPACE //#define QDNSLOOKUP_DEBUG @@ -118,7 +120,7 @@ public: , requestName(name) , nameserver(nameserver) { } - void run() Q_DECL_OVERRIDE; + void run() override; signals: void finished(const QDnsLookupReply &reply); diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index a1adc61c4c..bf00c6efce 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -64,32 +64,6 @@ QT_BEGIN_NAMESPACE - -class QHostAddressPrivate : public QSharedData -{ -public: - QHostAddressPrivate(); - - void setAddress(quint32 a_ = 0); - void setAddress(const quint8 *a_); - void setAddress(const Q_IPV6ADDR &a_); - - bool parse(const QString &ipString); - void clear(); - - QString scopeId; - - union { - Q_IPV6ADDR a6; // IPv6 address - struct { quint64 c[2]; } a6_64; - struct { quint32 c[4]; } a6_32; - }; - quint32 a; // IPv4 address - qint8 protocol; - - friend class QHostAddress; -}; - QHostAddressPrivate::QHostAddressPrivate() : a(0), protocol(QAbstractSocket::UnknownNetworkLayerProtocol) { @@ -205,6 +179,75 @@ void QHostAddressPrivate::clear() memset(&a6, 0, sizeof(a6)); } +AddressClassification QHostAddressPrivate::classify() const +{ + if (a) { + // This is an IPv4 address or an IPv6 v4-mapped address includes all + // IPv6 v4-compat addresses, except for ::ffff:0.0.0.0 (because `a' is + // zero). See setAddress(quint8*) below, which calls convertToIpv4(), + // for details. + // Source: RFC 5735 + if ((a & 0xff000000U) == 0x7f000000U) // 127.0.0.0/8 + return LoopbackAddress; + if ((a & 0xf0000000U) == 0xe0000000U) // 224.0.0.0/4 + return MulticastAddress; + if ((a & 0xffff0000U) == 0xa9fe0000U) // 169.254.0.0/16 + return LinkLocalAddress; + if ((a & 0xff000000U) == 0) // 0.0.0.0/8 except 0.0.0.0 (handled below) + return LocalNetAddress; + if ((a & 0xf0000000U) == 0xf0000000U) { // 240.0.0.0/4 + if (a == 0xffffffffU) // 255.255.255.255 + return BroadcastAddress; + return UnknownAddress; + } + + // Not testing for PrivateNetworkAddress and TestNetworkAddress + // since we don't need them yet. + return GlobalAddress; + } + + // As `a' is zero, this address is either ::ffff:0.0.0.0 or a non-v4-mapped IPv6 address. + // Source: https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml + if (a6_64.c[0]) { + quint32 high16 = qFromBigEndian(a6_32.c[0]) >> 16; + switch (high16 >> 8) { + case 0xff: // ff00::/8 + return MulticastAddress; + case 0xfe: + switch (high16 & 0xffc0) { + case 0xfec0: // fec0::/10 + return SiteLocalAddress; + + case 0xfe80: // fe80::/10 + return LinkLocalAddress; + + default: // fe00::/9 + return UnknownAddress; + } + case 0xfd: // fc00::/7 + case 0xfc: + return UniqueLocalAddress; + default: + return GlobalAddress; + } + } + + quint64 low64 = qFromBigEndian(a6_64.c[1]); + if (low64 == 1) // ::1 + return LoopbackAddress; + if (low64 >> 32 == 0xffff) { // ::ffff:0.0.0.0/96 + Q_ASSERT(quint32(low64) == 0); + return LocalNetAddress; + } + if (low64) // not :: + return GlobalAddress; + + if (protocol == QAbstractSocket::UnknownNetworkLayerProtocol) + return UnknownAddress; + + // only :: and 0.0.0.0 remain now + return LocalNetAddress; +} bool QNetmask::setAddress(const QHostAddress &address) { @@ -685,7 +728,7 @@ void QHostAddress::setAddress(SpecialAddress address) */ quint32 QHostAddress::toIPv4Address() const { - return toIPv4Address(Q_NULLPTR); + return toIPv4Address(nullptr); } /*! @@ -1154,21 +1197,91 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet) */ bool QHostAddress::isLoopback() const { - if ((d->a & 0xFF000000) == 0x7F000000) - return true; // v4 range (including IPv6 wrapped IPv4 addresses) - if (d->protocol == QAbstractSocket::IPv6Protocol) { -#ifdef __SSE2__ - const __m128i loopback = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); - __m128i ipv6 = _mm_loadu_si128((const __m128i *)d->a6.c); - __m128i cmp = _mm_cmpeq_epi8(ipv6, loopback); - return _mm_movemask_epi8(cmp) == 0xffff; -#else - if (d->a6_64.c[0] != 0 || qFromBigEndian(d->a6_64.c[1]) != 1) - return false; -#endif - return true; - } - return false; + return d->classify() == LoopbackAddress; +} + +/*! + \since 5.11 + + Returns \c true if the address is an IPv4 or IPv6 global address, \c false + otherwise. A global address is an address that is not reserved for + special purposes (like loopback or multicast) or future purposes. + + Note that IPv6 unique local unicast addresses are considered global + addresses (see isUniqueLocalUnicast()), as are IPv4 addresses reserved for + local networks by \l {https://tools.ietf.org/html/rfc1918}{RFC 1918}. + + Also note that IPv6 site-local addresses are deprecated and should be + considered as global in new applications. This function returns true for + site-local addresses too. + + \sa isLoopback(), isSiteLocal(), isUniqueLocalUnicast() +*/ +bool QHostAddress::isGlobal() const +{ + return d->classify() & GlobalAddress; // GlobalAddress is a bit +} + +/*! + \since 5.11 + + Returns \c true if the address is an IPv4 or IPv6 link-local address, \c + false otherwise. + + An IPv4 link-local address is an address in the network 169.254.0.0/16. An + IPv6 link-local address is one in the network fe80::/10. See the + \l{https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml}{IANA + IPv6 Address Space} registry for more information. + + \sa isLoopback(), isGlobal(). isMulticast(), isSiteLocal(), isUniqueLocalUnicast() +*/ +bool QHostAddress::isLinkLocal() const +{ + return d->classify() == LinkLocalAddress; +} + +/*! + \since 5.11 + + Returns \c true if the address is an IPv6 site-local address, \c + false otherwise. + + An IPv6 site-local address is one in the network fec0::/10. See the + \l{https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml}{IANA + IPv6 Address Space} registry for more information. + + IPv6 site-local addresses are deprecated and should not be depended upon in + new applications. New applications should not depend on this function and + should consider site-local addresses the same as global (which is why + isGlobal() also returns true). Site-local addresses were replaced by Unique + Local Addresses (ULA). + + \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast() +*/ +bool QHostAddress::isSiteLocal() const +{ + return d->classify() == SiteLocalAddress; +} + +/*! + \since 5.11 + + Returns \c true if the address is an IPv6 unique local unicast address, \c + false otherwise. + + An IPv6 unique local unicast address is one in the network fc00::/7. See the + \l{https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml} + {IANA IPv6 Address Space} registry for more information. + + Note that Unique local unicast addresses count as global addresses too. RFC + 4193 says that, in practice, "applications may treat these addresses like + global scoped addresses." Only routers need care about the distinction. + + \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast() +*/ +bool QHostAddress::isUniqueLocalUnicast() const +{ + return d->classify() == UniqueLocalAddress; } /*! @@ -1176,14 +1289,29 @@ bool QHostAddress::isLoopback() const Returns \c true if the address is an IPv4 or IPv6 multicast address, \c false otherwise. + + \sa isLoopback(), isGlobal(), isLinkLocal(), isSiteLocal(), isUniqueLocalUnicast() */ bool QHostAddress::isMulticast() const { - if ((d->a & 0xF0000000) == 0xE0000000) - return true; // 224.0.0.0-239.255.255.255 (including v4-mapped IPv6 addresses) - if (d->protocol == QAbstractSocket::IPv6Protocol) - return d->a6.c[0] == 0xff; - return false; + return d->classify() == MulticastAddress; +} + +/*! + \since 5.11 + + Returns \c true if the address is the IPv4 broadcast address, \c false + otherwise. The IPv4 broadcast address is 255.255.255.255. + + Note that this function does not return true for an IPv4 network's local + broadcast address. For that, please use \l QNetworkInterface to obtain the + broadcast addresses of the local machine. + + \sa isLoopback(), isGlobal(), isMulticast(), isLinkLocal(), isUniqueLocalUnicast() +*/ +bool QHostAddress::isBroadcast() const +{ + return d->classify() == BroadcastAddress; } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h index fdbdbfc72c..00555f3d8e 100644 --- a/src/network/kernel/qhostaddress.h +++ b/src/network/kernel/qhostaddress.h @@ -148,12 +148,18 @@ public: bool isInSubnet(const QPair<QHostAddress, int> &subnet) const; bool isLoopback() const; + bool isGlobal() const; + bool isLinkLocal() const; + bool isSiteLocal() const; + bool isUniqueLocalUnicast() const; bool isMulticast() const; + bool isBroadcast() const; static QPair<QHostAddress, int> parseSubnet(const QString &subnet); friend Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed) Q_DECL_NOTHROW; protected: + friend class QHostAddressPrivate; QExplicitlySharedDataPointer<QHostAddressPrivate> d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QHostAddress::ConversionMode) diff --git a/src/network/kernel/qhostaddress_p.h b/src/network/kernel/qhostaddress_p.h index 5106760ed9..4dc2989011 100644 --- a/src/network/kernel/qhostaddress_p.h +++ b/src/network/kernel/qhostaddress_p.h @@ -57,6 +57,22 @@ QT_BEGIN_NAMESPACE +enum AddressClassification { + LoopbackAddress = 1, + LocalNetAddress, // RFC 1122 + LinkLocalAddress, // RFC 4291 (v6), RFC 3927 (v4) + MulticastAddress, // RFC 4291 (v6), RFC 3171 (v4) + BroadcastAddress, // RFC 919, 922 + + GlobalAddress = 16, + TestNetworkAddress, // RFC 3849 (v6), RFC 5737 (v4), + PrivateNetworkAddress, // RFC 1918 + UniqueLocalAddress, // RFC 4193 + SiteLocalAddress, // RFC 4291 (deprecated by RFC 3879, should be treated as global) + + UnknownAddress = 0 // unclassified or reserved +}; + class QNetmask { // stores 0-32 for IPv4, 0-128 for IPv6, or 255 for invalid @@ -85,6 +101,35 @@ public: { return n1.length == n2.length; } }; +class QHostAddressPrivate : public QSharedData +{ +public: + QHostAddressPrivate(); + + void setAddress(quint32 a_ = 0); + void setAddress(const quint8 *a_); + void setAddress(const Q_IPV6ADDR &a_); + + bool parse(const QString &ipString); + void clear(); + + QString scopeId; + + union { + Q_IPV6ADDR a6; // IPv6 address + struct { quint64 c[2]; } a6_64; + struct { quint32 c[4]; } a6_32; + }; + quint32 a; // IPv4 address + qint8 protocol; + + AddressClassification classify() const; + static AddressClassification classify(const QHostAddress &address) + { return address.d->classify(); } + + friend class QHostAddress; +}; + QT_END_NAMESPACE #endif diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index dd46818a19..d1da814e54 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -194,7 +194,7 @@ public: QHostInfoRunnable(const QString &hn, int i); QHostInfoRunnable(const QString &hn, int i, const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj); - void run() Q_DECL_OVERRIDE; + void run() override; QString toBeLookedUp; int id; @@ -225,7 +225,7 @@ public: QHostInfoLookupManager(); ~QHostInfoLookupManager(); - void clear() Q_DECL_OVERRIDE; + void clear() override; void work(); // called from QHostInfo diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index 8d2cffc304..d22608e22f 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -79,6 +79,11 @@ QT_BEGIN_NAMESPACE # define Q_ADDRCONFIG AI_ADDRCONFIG #endif +enum LibResolvFeature { + NeedResInit, + NeedResNInit +}; + typedef struct __res_state *res_state_ptr; typedef int (*res_init_proto)(void); @@ -89,9 +94,29 @@ typedef void (*res_nclose_proto)(res_state_ptr); static res_nclose_proto local_res_nclose = 0; static res_state_ptr local_res = 0; -static bool resolveLibraryInternal() -{ #if QT_CONFIG(library) && !defined(Q_OS_QNX) +namespace { +struct LibResolv +{ + enum { +#ifdef RES_NORELOAD + // If RES_NORELOAD is defined, then the libc is capable of watching + // /etc/resolv.conf for changes and reloading as necessary. So accept + // whatever is configured. + ReinitNecessary = false +#else + ReinitNecessary = true +#endif + }; + + QLibrary lib; + LibResolv(); + ~LibResolv() { lib.unload(); } +}; +} + +LibResolv::LibResolv() +{ QLibrary lib; #ifdef LIBRESOLV_SO lib.setFileName(QStringLiteral(LIBRESOLV_SO)); @@ -100,32 +125,45 @@ static bool resolveLibraryInternal() { lib.setFileName(QLatin1String("resolv")); if (!lib.load()) - return false; + return; } - local_res_init = res_init_proto(lib.resolve("__res_init")); - if (!local_res_init) - local_res_init = res_init_proto(lib.resolve("res_init")); - + // res_ninit is required for localDomainName() local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); if (!local_res_ninit) local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); - - if (!local_res_ninit) { - // if we can't get a thread-safe context, we have to use the global _res state - local_res = res_state_ptr(lib.resolve("_res")); - } else { + if (local_res_ninit) { + // we must now find res_nclose local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); if (!local_res_nclose) local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); if (!local_res_nclose) - local_res_ninit = 0; + local_res_ninit = nullptr; } -#endif - return true; + if (ReinitNecessary || !local_res_ninit) { + local_res_init = res_init_proto(lib.resolve("__res_init")); + if (!local_res_init) + local_res_init = res_init_proto(lib.resolve("res_init")); + + if (local_res_init && !local_res_ninit) { + // if we can't get a thread-safe context, we have to use the global _res state + local_res = res_state_ptr(lib.resolve("_res")); + } + } +} +Q_GLOBAL_STATIC(LibResolv, libResolv) + +static void resolveLibrary(LibResolvFeature f) +{ + if (LibResolv::ReinitNecessary || f == NeedResNInit) + libResolv(); +} +#else // QT_CONFIG(library) || Q_OS_QNX +static void resolveLibrary(LibResolvFeature) +{ } -Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal())) +#endif // QT_CONFIG(library) || Q_OS_QNX QHostInfo QHostInfoAgent::fromName(const QString &hostName) { @@ -137,7 +175,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) #endif // Load res_init on demand. - resolveLibrary(); + resolveLibrary(NeedResInit); // If res_init is available, poll it. if (local_res_init) @@ -275,7 +313,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QString QHostInfo::localDomainName() { #if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID) - resolveLibrary(); + resolveLibrary(NeedResNInit); if (local_res_ninit) { // using thread-safe version res_state_ptr state = res_state_ptr(malloc(sizeof(*state))); diff --git a/src/network/kernel/qnetworkdatagram.cpp b/src/network/kernel/qnetworkdatagram.cpp index d167190684..50421fa7f5 100644 --- a/src/network/kernel/qnetworkdatagram.cpp +++ b/src/network/kernel/qnetworkdatagram.cpp @@ -442,10 +442,11 @@ void QNetworkDatagram::setData(const QByteArray &data) } /*! - \fn QNetworkDatagram QNetworkDatagram::makeReply(const QByteArray &data) const + \fn QNetworkDatagram QNetworkDatagram::makeReply(const QByteArray &payload) const & + \fn QNetworkDatagram QNetworkDatagram::makeReply(const QByteArray &payload) && Creates a new QNetworkDatagram representing a reply to this incoming datagram - and sets the payload data to \a data. This function is a very convenient + and sets the payload data to \a payload. This function is a very convenient way of responding to a datagram back to the original sender. Example: @@ -495,6 +496,7 @@ void QNetworkDatagram::setData(const QByteArray &data) \endcode */ + static bool isNonMulticast(const QHostAddress &addr) { // is it a multicast address? @@ -528,6 +530,11 @@ void QNetworkDatagram::destroy(QNetworkDatagramPrivate *d) delete d; } +/*! \fn void QNetworkDatagram::swap(QNetworkDatagram &other) + Swaps this instance with \a other. +*/ + + QT_END_NAMESPACE #endif // QT_NO_UDPSOCKET diff --git a/src/network/kernel/qnetworkdatagram.h b/src/network/kernel/qnetworkdatagram.h index fa994d6170..1acb44a1e0 100644 --- a/src/network/kernel/qnetworkdatagram.h +++ b/src/network/kernel/qnetworkdatagram.h @@ -63,7 +63,7 @@ public: QNetworkDatagram(QNetworkDatagram &&other) Q_DECL_NOTHROW : d(other.d) - { other.d = Q_NULLPTR; } + { other.d = nullptr; } QNetworkDatagram &operator=(QNetworkDatagram &&other) Q_DECL_NOTHROW { swap(other); return *this; } @@ -91,7 +91,7 @@ public: QByteArray data() const; void setData(const QByteArray &data); -#ifdef Q_COMPILER_REF_QUALIFIERS +#if defined(Q_COMPILER_REF_QUALIFIERS) || defined(Q_CLANG_QDOC) QNetworkDatagram makeReply(const QByteArray &payload) const & { return makeReply_helper(payload); } QNetworkDatagram makeReply(const QByteArray &payload) && diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp index 3857ff87b9..3fb0dc80ee 100644 --- a/src/network/kernel/qnetworkinterface.cpp +++ b/src/network/kernel/qnetworkinterface.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2017 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtNetwork module of the Qt Toolkit. @@ -59,19 +59,15 @@ static QList<QNetworkInterfacePrivate *> postProcess(QList<QNetworkInterfacePriv // The math is: // broadcast = IP | ~netmask - QList<QNetworkInterfacePrivate *>::Iterator it = list.begin(); - const QList<QNetworkInterfacePrivate *>::Iterator end = list.end(); - for ( ; it != end; ++it) { - QList<QNetworkAddressEntry>::Iterator addr_it = (*it)->addressEntries.begin(); - const QList<QNetworkAddressEntry>::Iterator addr_end = (*it)->addressEntries.end(); - for ( ; addr_it != addr_end; ++addr_it) { - if (addr_it->ip().protocol() != QAbstractSocket::IPv4Protocol) + for (QNetworkInterfacePrivate *interface : list) { + for (QNetworkAddressEntry &address : interface->addressEntries) { + if (address.ip().protocol() != QAbstractSocket::IPv4Protocol) continue; - if (!addr_it->netmask().isNull() && addr_it->broadcast().isNull()) { - QHostAddress bcast = addr_it->ip(); - bcast = QHostAddress(bcast.toIPv4Address() | ~addr_it->netmask().toIPv4Address()); - addr_it->setBroadcast(bcast); + if (!address.netmask().isNull() && address.broadcast().isNull()) { + QHostAddress bcast = address.ip(); + bcast = QHostAddress(bcast.toIPv4Address() | ~address.netmask().toIPv4Address()); + address.setBroadcast(bcast); } } } @@ -91,17 +87,16 @@ QNetworkInterfaceManager::~QNetworkInterfaceManager() QSharedDataPointer<QNetworkInterfacePrivate> QNetworkInterfaceManager::interfaceFromName(const QString &name) { - QList<QSharedDataPointer<QNetworkInterfacePrivate> > interfaceList = allInterfaces(); - QList<QSharedDataPointer<QNetworkInterfacePrivate> >::ConstIterator it = interfaceList.constBegin(); + const auto interfaceList = allInterfaces(); bool ok; uint index = name.toUInt(&ok); - for ( ; it != interfaceList.constEnd(); ++it) { - if (ok && (*it)->index == int(index)) - return *it; - else if ((*it)->name == name) - return *it; + for (const auto &interface : interfaceList) { + if (ok && interface->index == int(index)) + return interface; + else if (interface->name == name) + return interface; } return empty; @@ -109,11 +104,11 @@ QSharedDataPointer<QNetworkInterfacePrivate> QNetworkInterfaceManager::interface QSharedDataPointer<QNetworkInterfacePrivate> QNetworkInterfaceManager::interfaceFromIndex(int index) { - QList<QSharedDataPointer<QNetworkInterfacePrivate> > interfaceList = allInterfaces(); - QList<QSharedDataPointer<QNetworkInterfacePrivate> >::ConstIterator it = interfaceList.constBegin(); - for ( ; it != interfaceList.constEnd(); ++it) - if ((*it)->index == index) - return *it; + const auto interfaceList = allInterfaces(); + for (const auto &interface : interfaceList) { + if (interface->index == index) + return interface; + } return empty; } @@ -124,8 +119,15 @@ QList<QSharedDataPointer<QNetworkInterfacePrivate> > QNetworkInterfaceManager::a QList<QSharedDataPointer<QNetworkInterfacePrivate> > result; result.reserve(list.size()); - for (QNetworkInterfacePrivate *ptr : list) + for (QNetworkInterfacePrivate *ptr : list) { + if ((ptr->flags & QNetworkInterface::IsUp) == 0) { + // if the network interface isn't UP, the addresses are ineligible for DNS + for (auto &addr : ptr->addressEntries) + addr.setDnsEligibility(QNetworkAddressEntry::DnsIneligible); + } + result << QSharedDataPointer<QNetworkInterfacePrivate>(ptr); + } return result; } @@ -164,6 +166,32 @@ QString QNetworkInterfacePrivate::makeHwAddress(int len, uchar *data) */ /*! + \enum QNetworkAddressEntry::DnsEligilibilityStatus + \since 5.11 + + This enum indicates whether a given host address is eligible to be + published in the Domain Name System (DNS) or other similar name resolution + mechanisms. In general, an address is suitable for publication if it is an + address this machine will be reached at for an indeterminate amount of + time, though it need not be permanent. For example, addresses obtained via + DHCP are often eligible, but cryptographically-generated temporary IPv6 + addresses are not. + + \value DnsEligibilityUnknown Qt and the operating system could not determine + whether this address should be published or not. + The application may need to apply further + heuristics if it cannot find any eligible + addresses. + \value DnsEligible This address is eligible for publication in DNS. + \value DnsIneligible This address should not be published in DNS and + should not be transmitted to other parties, + except maybe as the source address of an outgoing + packet. + + \sa dnsEligibility(), setDnsEligibility() +*/ + +/*! Constructs an empty QNetworkAddressEntry object. */ QNetworkAddressEntry::QNetworkAddressEntry() @@ -218,6 +246,39 @@ bool QNetworkAddressEntry::operator==(const QNetworkAddressEntry &other) const } /*! + \since 5.11 + + Returns whether this address is eligible for publication in the Domain Name + System (DNS) or similar name resolution mechanisms. + + In general, an address is suitable for publication if it is an address this + machine will be reached at for an indeterminate amount of time, though it + need not be permanent. For example, addresses obtained via DHCP are often + eligible, but cryptographically-generated temporary IPv6 addresses are not. + + On some systems, QNetworkInterface will need to heuristically determine + which addresses are eligible. + + \sa isLifetimeKnown(), isPermanent(), setDnsEligibility() +*/ +QNetworkAddressEntry::DnsEligibilityStatus QNetworkAddressEntry::dnsEligibility() const +{ + return d->dnsEligibility; +} + +/*! + \since 5.11 + + Sets the DNS eligibility flag for this address to \a status. + + \sa dnsEligibility() +*/ +void QNetworkAddressEntry::setDnsEligibility(DnsEligibilityStatus status) +{ + d->dnsEligibility = status; +} + +/*! \fn bool QNetworkAddressEntry::operator!=(const QNetworkAddressEntry &other) const Returns \c true if this network address entry is different from \a @@ -340,6 +401,122 @@ void QNetworkAddressEntry::setBroadcast(const QHostAddress &newBroadcast) } /*! + \since 5.11 + + Returns \c true if the address lifetime is known, \c false if not. If the + lifetime is not known, both preferredLifetime() and validityLifetime() will + return QDeadlineTimer::Forever. + + \sa preferredLifetime(), validityLifetime(), setAddressLifetime(), clearAddressLifetime() +*/ +bool QNetworkAddressEntry::isLifetimeKnown() const +{ + return d->lifetimeKnown; +} + +/*! + \since 5.11 + + Returns the deadline when this address becomes deprecated (no longer + preferred), if known. If the address lifetime is not known (see + isLifetimeKnown()), this function always returns QDeadlineTimer::Forever. + + While an address is preferred, it may be used by the operating system as + the source address for new, outgoing packets. After it becomes deprecated, + it will remain valid for incoming packets for a while longer until finally + removed (see validityLifetime()). + + \sa validityLifetime(), isLifetimeKnown(), setAddressLifetime(), clearAddressLifetime() +*/ +QDeadlineTimer QNetworkAddressEntry::preferredLifetime() const +{ + return d->preferredLifetime; +} + +/*! + \since 5.11 + + Returns the deadline when this address becomes invalid and will be removed + from the networking stack, if known. If the address lifetime is not known + (see isLifetimeKnown()), this function always returns + QDeadlineTimer::Forever. + + While an address is valid, it will be accepted by the operating system as a + valid destination address for this machine. Whether it is used as a source + address for new, outgoing packets is controlled by, among other rules, the + preferred lifetime (see preferredLifetime()). + + \sa preferredLifetime(), isLifetimeKnown(), setAddressLifetime(), clearAddressLifetime() +*/ +QDeadlineTimer QNetworkAddressEntry::validityLifetime() const +{ + return d->validityLifetime; +} + +/*! + \since 5.11 + + Sets both the preferred and valid lifetimes for this address to the \a + preferred and \a validity deadlines, respectively. After this call, + isLifetimeKnown() will return \c true, even if both parameters are + QDeadlineTimer::Forever. + + \sa preferredLifetime(), validityLifetime(), isLifetimeKnown(), clearAddressLifetime() +*/ +void QNetworkAddressEntry::setAddressLifetime(QDeadlineTimer preferred, QDeadlineTimer validity) +{ + d->preferredLifetime = preferred; + d->validityLifetime = validity; + d->lifetimeKnown = true; +} + +/*! + \since 5.11 + + Resets both the preferred and valid lifetimes for this address. After this + call, isLifetimeKnown() will return \c false. + + \sa preferredLifetime(), validityLifetime(), isLifetimeKnown(), setAddressLifetime() +*/ +void QNetworkAddressEntry::clearAddressLifetime() +{ + d->preferredLifetime = QDeadlineTimer::Forever; + d->validityLifetime = QDeadlineTimer::Forever; + d->lifetimeKnown = false; +} + +/*! + \since 5.11 + + Returns \c true if this address is permanent on this interface, \c false if + it's temporary. A permenant address is one which has no expiration time and + is often static (manually configured). + + If this information could not be determined, this function returns \c true. + + \note Depending on the operating system and the networking configuration + tool, it is possible for a temporary address to be interpreted as + permanent, if the tool did not inform the details correctly to the + operating system. + + \sa isLifetimeKnown(), validityLifetime(), isTemporary() +*/ +bool QNetworkAddressEntry::isPermanent() const +{ + return d->validityLifetime.isForever(); +} + +/*! + \fn bool QNetworkAddressEntry::isTemporary() const + \since 5.11 + + Returns \c true if this address is temporary on this interface, \c false if + it's permanent. + + \sa isLifetimeKnown(), validityLifetime(), isPermanent() +*/ + +/*! \class QNetworkInterface \brief The QNetworkInterface class provides a listing of the host's IP addresses and network interfaces. @@ -396,6 +573,57 @@ void QNetworkAddressEntry::setBroadcast(const QHostAddress &newBroadcast) */ /*! + \enum QNetworkInterface::InterfaceType + + Specifies the type of hardware (PHY layer, OSI level 1) this interface is, + if it could be determined. Interface types that are not among those listed + below will generally be listed as Unknown, though future versions of Qt may + add new enumeration values. + + The possible values are: + + \value Unknown The interface type could not be determined or is not + one of the other listed types. + \value Loopback The virtual loopback interface, which is assigned + the loopback IP addresses (127.0.0.1, ::1). + \value Virtual A type of interface determined to be virtual, but + not any of the other possible types. For example, + tunnel interfaces are (currently) detected as + virtual ones. + \value Ethernet IEEE 802.3 Ethernet interfaces, though on many + systems other types of IEEE 802 interfaces may also + be detected as Ethernet (especially Wi-Fi). + \value WiFi IEEE 802.11 Wi-Fi interfaces. Note that on some + systems, QNetworkInterface may be unable to + distinguish regular Ethernet from Wi-Fi and will + not return this enum value. + \value Ieee80211 An alias for WiFi. + \value CanBus ISO 11898 Controller Area Network bus interfaces, + usually found on automotive systems. + \value Fddi ANSI X3T12 Fiber Distributed Data Interface, a local area + network over optical fibers. + \value Ppp Point-to-Point Protocol interfaces, establishing a + direct connection between two nodes over a lower + transport layer (often serial over radio or physical + line). + \value Slip Serial Line Internet Protocol interfaces. + \value Phonet Interfaces using the Linux Phonet socket family, for + communication with cellular modems. See the + \l {https://www.kernel.org/doc/Documentation/networking/phonet.txt}{Linux kernel documentation} + for more information. + \value Ieee802154 IEEE 802.15.4 Personal Area Network interfaces, other + than 6LoWPAN (see below). + \value SixLoWPAN 6LoWPAN (IPv6 over Low-power Wireless Personal Area + Networks) interfaces, which operate on IEEE 802.15.4 + PHY, but have specific header compression schemes + for IPv6 and UDP. This type of interface is often + used for mesh networking. + \value Ieee80216 IEEE 802.16 Wireless Metropolitan Area Network, also + known under the commercial name "WiMAX". + \value Ieee1394 IEEE 1394 interfaces (a.k.a. "FireWire"). +*/ + +/*! Constructs an empty network interface object. */ QNetworkInterface::QNetworkInterface() @@ -461,6 +689,29 @@ int QNetworkInterface::index() const } /*! + \since 5.11 + + Returns the maximum transmission unit on this interface, if known, or 0 + otherwise. + + The maximum transmission unit is the largest packet that may be sent on + this interface without incurring link-level fragmentation. Applications may + use this value to calculate the size of the payload that will fit an + unfragmented UDP datagram. Remember to subtract the sizes of headers used + in your communication over the interface, e.g. TCP (20 bytes) or UDP (12), + IPv4 (20) or IPv6 (40, absent some form of header compression), when + computing how big a payload you can transmit. Also note that the MTU along + the full path (the Path MTU) to the destination may be smaller than the + interface's MTU. + + \sa QUdpSocket +*/ +int QNetworkInterface::maxTransmissionUnit() const +{ + return d ? d->mtu : 0; +} + +/*! Returns the name of this network interface. On Unix systems, this is a string containing the type of the interface and optionally a sequence number, such as "eth0", "lo" or "pcn0". On Windows, it's @@ -499,6 +750,19 @@ QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const } /*! + \since 5.11 + + Returns the type of this interface, if it could be determined. If it could + not be determined, this function returns QNetworkInterface::Unknown. + + \sa hardwareAddress() +*/ +QNetworkInterface::InterfaceType QNetworkInterface::type() const +{ + return d ? d->type : Unknown; +} + +/*! Returns the low-level hardware address for this interface. On Ethernet interfaces, this will be a MAC address in string representation, separated by colons. @@ -506,6 +770,8 @@ QNetworkInterface::InterfaceFlags QNetworkInterface::flags() const Other interface types may have other types of hardware addresses. Implementations should not depend on this function returning a valid MAC address. + + \sa type() */ QString QNetworkInterface::hardwareAddress() const { @@ -691,4 +957,6 @@ QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface) QT_END_NAMESPACE +#include "moc_qnetworkinterface.cpp" + #endif // QT_NO_NETWORKINTERFACE diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h index c31621c3cb..f7ef192dc0 100644 --- a/src/network/kernel/qnetworkinterface.h +++ b/src/network/kernel/qnetworkinterface.h @@ -49,13 +49,19 @@ QT_BEGIN_NAMESPACE - +class QDeadlineTimer; template<typename T> class QList; class QNetworkAddressEntryPrivate; class Q_NETWORK_EXPORT QNetworkAddressEntry { public: + enum DnsEligibilityStatus : qint8 { + DnsEligibilityUnknown = -1, + DnsIneligible = 0, + DnsEligible = 1 + }; + QNetworkAddressEntry(); QNetworkAddressEntry(const QNetworkAddressEntry &other); #ifdef Q_COMPILER_RVALUE_REFS @@ -70,6 +76,9 @@ public: inline bool operator!=(const QNetworkAddressEntry &other) const { return !(*this == other); } + DnsEligibilityStatus dnsEligibility() const; + void setDnsEligibility(DnsEligibilityStatus status); + QHostAddress ip() const; void setIp(const QHostAddress &newIp); @@ -81,6 +90,14 @@ public: QHostAddress broadcast() const; void setBroadcast(const QHostAddress &newBroadcast); + bool isLifetimeKnown() const; + QDeadlineTimer preferredLifetime() const; + QDeadlineTimer validityLifetime() const; + void setAddressLifetime(QDeadlineTimer preferred, QDeadlineTimer validity); + void clearAddressLifetime(); + bool isPermanent() const; + bool isTemporary() const { return !isPermanent(); } + private: QScopedPointer<QNetworkAddressEntryPrivate> d; }; @@ -90,6 +107,7 @@ Q_DECLARE_SHARED(QNetworkAddressEntry) class QNetworkInterfacePrivate; class Q_NETWORK_EXPORT QNetworkInterface { + Q_GADGET public: enum InterfaceFlag { IsUp = 0x1, @@ -100,6 +118,27 @@ public: CanMulticast = 0x20 }; Q_DECLARE_FLAGS(InterfaceFlags, InterfaceFlag) + Q_FLAG(InterfaceFlags) + + enum InterfaceType { + Loopback = 1, + Virtual, + Ethernet, + Slip, + CanBus, + Ppp, + Fddi, + Wifi, + Ieee80211 = Wifi, // alias + Phonet, + Ieee802154, + SixLoWPAN, // 6LoWPAN, but we can't start with a digit + Ieee80216, + Ieee1394, + + Unknown = 0 + }; + Q_ENUM(InterfaceType) QNetworkInterface(); QNetworkInterface(const QNetworkInterface &other); @@ -114,9 +153,11 @@ public: bool isValid() const; int index() const; + int maxTransmissionUnit() const; QString name() const; QString humanReadableName() const; InterfaceFlags flags() const; + InterfaceType type() const; QString hardwareAddress() const; QList<QNetworkAddressEntry> addressEntries() const; diff --git a/src/network/kernel/qnetworkinterface_linux.cpp b/src/network/kernel/qnetworkinterface_linux.cpp new file mode 100644 index 0000000000..01b2811070 --- /dev/null +++ b/src/network/kernel/qnetworkinterface_linux.cpp @@ -0,0 +1,443 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkinterface.h" +#include "qnetworkinterface_p.h" +#include "qnetworkinterface_unix_p.h" + +#include <qendian.h> +#include <qobjectdefs.h> +#include <qvarlengtharray.h> + +// accordding to rtnetlink(7) +#include <asm/types.h> +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <linux/wireless.h> +#include <sys/socket.h> + +/* in case these aren't defined in linux/if_arp.h (added since 2.6.28) */ +#define ARPHRD_PHONET 820 /* v2.6.29: PhoNet media type */ +#define ARPHRD_PHONET_PIPE 821 /* v2.6.29: PhoNet pipe header */ +#define ARPHRD_IEEE802154 804 /* v2.6.31 */ +#define ARPHRD_6LOWPAN 825 /* v3.14: IPv6 over LoWPAN */ + +QT_BEGIN_NAMESPACE + +enum { + BufferSize = 8192 +}; + +static QNetworkInterface::InterfaceType probeIfType(int socket, struct ifreq *req, short arptype) +{ + switch (ushort(arptype)) { + case ARPHRD_LOOPBACK: + return QNetworkInterface::Loopback; + + case ARPHRD_ETHER: + // check if it's a WiFi interface + if (qt_safe_ioctl(socket, SIOCGIWMODE, req) >= 0) + return QNetworkInterface::Wifi; + return QNetworkInterface::Ethernet; + + case ARPHRD_SLIP: + case ARPHRD_CSLIP: + case ARPHRD_SLIP6: + case ARPHRD_CSLIP6: + return QNetworkInterface::Slip; + + case ARPHRD_CAN: + return QNetworkInterface::CanBus; + + case ARPHRD_PPP: + return QNetworkInterface::Ppp; + + case ARPHRD_FDDI: + return QNetworkInterface::Fddi; + + case ARPHRD_IEEE80211: + case ARPHRD_IEEE80211_PRISM: + case ARPHRD_IEEE80211_RADIOTAP: + return QNetworkInterface::Ieee80211; + + case ARPHRD_IEEE802154: + return QNetworkInterface::Ieee802154; + + case ARPHRD_PHONET: + case ARPHRD_PHONET_PIPE: + return QNetworkInterface::Phonet; + + case ARPHRD_6LOWPAN: + return QNetworkInterface::SixLoWPAN; + + case ARPHRD_TUNNEL: + case ARPHRD_TUNNEL6: + case ARPHRD_NONE: + case ARPHRD_VOID: + return QNetworkInterface::Virtual; + } + return QNetworkInterface::Unknown; +} + + +namespace { +struct NetlinkSocket +{ + int sock; + NetlinkSocket(int bufferSize) + { + sock = qt_safe_socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (Q_UNLIKELY(sock == -1)) + qErrnoWarning("Could not create AF_NETLINK socket"); + + // set buffer length + socklen_t len = sizeof(bufferSize); + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufferSize, len); + } + + ~NetlinkSocket() + { + if (sock != -1) + qt_safe_close(sock); + } + + operator int() const { return sock; } +}; + +template <typename Lambda> struct ProcessNetlinkRequest +{ + using FunctionTraits = QtPrivate::FunctionPointer<decltype(&Lambda::operator())>; + using FirstArgument = typename FunctionTraits::Arguments::Car; + + static int expectedTypeForRequest(int rtype) + { + Q_STATIC_ASSERT(RTM_NEWADDR == RTM_GETADDR - 2); + Q_STATIC_ASSERT(RTM_NEWLINK == RTM_GETLINK - 2); + Q_ASSERT(rtype == RTM_GETADDR || rtype == RTM_GETLINK); + return rtype - 2; + } + + void operator()(int sock, nlmsghdr *hdr, char *buf, size_t bufsize, Lambda &&func) + { + // send the request + if (send(sock, hdr, hdr->nlmsg_len, 0) != ssize_t(hdr->nlmsg_len)) + return; + + // receive and parse the request + int expectedType = expectedTypeForRequest(hdr->nlmsg_type); + const bool isDump = hdr->nlmsg_flags & NLM_F_DUMP; + forever { + qsizetype len = recv(sock, buf, bufsize, 0); + hdr = reinterpret_cast<struct nlmsghdr *>(buf); + if (!NLMSG_OK(hdr, len)) + return; + + auto arg = reinterpret_cast<FirstArgument>(NLMSG_DATA(hdr)); + size_t payloadLen = NLMSG_PAYLOAD(hdr, 0); + + // is this a multipart message? + Q_ASSERT(isDump == !!(hdr->nlmsg_flags & NLM_F_MULTI)); + if (!isDump) { + // no, single message + if (hdr->nlmsg_type == expectedType && payloadLen >= sizeof(FirstArgument)) + return void(func(arg, payloadLen)); + } else { + // multipart, parse until done + do { + if (hdr->nlmsg_type == NLMSG_DONE) + return; + if (hdr->nlmsg_type != expectedType || payloadLen < sizeof(FirstArgument)) + break; + func(arg, payloadLen); + + // NLMSG_NEXT also updates the len variable + hdr = NLMSG_NEXT(hdr, len); + arg = reinterpret_cast<FirstArgument>(NLMSG_DATA(hdr)); + payloadLen = NLMSG_PAYLOAD(hdr, 0); + } while (NLMSG_OK(hdr, len)); + + if (len == 0) + continue; // get new datagram + } + +#ifndef QT_NO_DEBUG + if (NLMSG_OK(hdr, len)) + qWarning("QNetworkInterface/AF_NETLINK: received unknown packet type (%d) or too short (%u)", + hdr->nlmsg_type, hdr->nlmsg_len); + else + qWarning("QNetworkInterface/AF_NETLINK: received invalid packet with size %d", int(len)); +#endif + return; + } + } +}; + +template <typename Lambda> +void processNetlinkRequest(int sock, struct nlmsghdr *hdr, char *buf, size_t bufsize, Lambda &&l) +{ + ProcessNetlinkRequest<Lambda>()(sock, hdr, buf, bufsize, std::forward<Lambda>(l)); +} +} + +uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name) +{ + uint index = 0; + if (name.length() >= IFNAMSIZ) + return index; + + int socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0); + if (socket >= 0) { + struct ifreq req; + req.ifr_ifindex = 0; + strcpy(req.ifr_name, name.toLatin1().constData()); + + if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0) + index = req.ifr_ifindex; + qt_safe_close(socket); + } + return index; +} + +QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) +{ + int socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0); + if (socket >= 0) { + struct ifreq req; + req.ifr_ifindex = index; + + if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) { + qt_safe_close(socket); + return QString::fromLatin1(req.ifr_name); + } + qt_safe_close(socket); + } + return QString(); +} + +static QList<QNetworkInterfacePrivate *> getInterfaces(int sock, char *buf) +{ + QList<QNetworkInterfacePrivate *> result; + struct ifreq req; + + // request all links + struct { + struct nlmsghdr req; + struct ifinfomsg ifi; + } ifi_req; + memset(&ifi_req, 0, sizeof(ifi_req)); + + ifi_req.req.nlmsg_len = sizeof(ifi_req); + ifi_req.req.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + ifi_req.req.nlmsg_type = RTM_GETLINK; + + // parse the interfaces + processNetlinkRequest(sock, &ifi_req.req, buf, BufferSize, [&](ifinfomsg *ifi, size_t len) { + auto iface = new QNetworkInterfacePrivate; + iface->index = ifi->ifi_index; + iface->flags = convertFlags(ifi->ifi_flags); + + // read attributes + auto rta = reinterpret_cast<struct rtattr *>(ifi + 1); + len -= sizeof(*ifi); + for ( ; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + int payloadLen = RTA_PAYLOAD(rta); + auto payloadPtr = reinterpret_cast<char *>(RTA_DATA(rta)); + + switch (rta->rta_type) { + case IFLA_ADDRESS: // link-level address + iface->hardwareAddress = + iface->makeHwAddress(payloadLen, reinterpret_cast<uchar *>(payloadPtr)); + break; + + case IFLA_IFNAME: // interface name + Q_ASSERT(payloadLen <= int(sizeof(req.ifr_name))); + memcpy(req.ifr_name, payloadPtr, payloadLen); // including terminating NUL + iface->name = QString::fromLatin1(payloadPtr, payloadLen - 1); + break; + + case IFLA_MTU: + Q_ASSERT(payloadLen == sizeof(int)); + iface->mtu = *reinterpret_cast<int *>(payloadPtr); + break; + + case IFLA_OPERSTATE: // operational state + if (*payloadPtr != IF_OPER_UNKNOWN) { + // override the flag + iface->flags &= ~QNetworkInterface::IsUp; + if (*payloadPtr == IF_OPER_UP) + iface->flags |= QNetworkInterface::IsUp; + } + break; + } + } + + if (Q_UNLIKELY(iface->name.isEmpty())) { + qWarning("QNetworkInterface: found interface %d with no name", iface->index); + delete iface; + } else { + iface->type = probeIfType(sock, &req, ifi->ifi_type); + result.append(iface); + } + }); + return result; +} + +static void getAddresses(int sock, char *buf, QList<QNetworkInterfacePrivate *> &result) +{ + // request all addresses + struct { + struct nlmsghdr req; + struct ifaddrmsg ifa; + } ifa_req; + memset(&ifa_req, 0, sizeof(ifa_req)); + + ifa_req.req.nlmsg_len = sizeof(ifa_req); + ifa_req.req.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + ifa_req.req.nlmsg_type = RTM_GETADDR; + ifa_req.req.nlmsg_seq = 1; + + // parse the addresses + processNetlinkRequest(sock, &ifa_req.req, buf, BufferSize, [&](ifaddrmsg *ifa, size_t len) { + if (Q_UNLIKELY(ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6)) { + // unknown address types + return; + } + + // find the interface this is relevant to + QNetworkInterfacePrivate *iface = nullptr; + for (auto candidate : qAsConst(result)) { + if (candidate->index != int(ifa->ifa_index)) + continue; + iface = candidate; + break; + } + + if (Q_UNLIKELY(!iface)) { + qWarning("QNetworkInterface/AF_NETLINK: found unknown interface with index %d", ifa->ifa_index); + return; + } + + QNetworkAddressEntry entry; + quint32 flags = ifa->ifa_flags; // may be overwritten by IFA_FLAGS + + auto makeAddress = [=](uchar *ptr, int len) { + QHostAddress addr; + if (ifa->ifa_family == AF_INET) { + Q_ASSERT(len == 4); + addr.setAddress(qFromBigEndian<quint32>(ptr)); + } else { + Q_ASSERT(len == 16); + addr.setAddress(ptr); + + // do we need a scope ID? + if (addr.isLinkLocal()) + addr.setScopeId(iface->name); + } + return addr; + }; + + // read attributes + auto rta = reinterpret_cast<struct rtattr *>(ifa + 1); + len -= sizeof(*ifa); + for ( ; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + int payloadLen = RTA_PAYLOAD(rta); + auto payloadPtr = reinterpret_cast<uchar *>(RTA_DATA(rta)); + + switch (rta->rta_type) { + case IFA_ADDRESS: // address + entry.setIp(makeAddress(payloadPtr, payloadLen)); + break; + + case IFA_BROADCAST: + Q_ASSERT(ifa->ifa_family == AF_INET); + entry.setBroadcast(makeAddress(payloadPtr, payloadLen)); + break; + + case IFA_CACHEINFO: + if (size_t(payloadLen) >= sizeof(ifa_cacheinfo)) { + auto cacheinfo = reinterpret_cast<ifa_cacheinfo *>(payloadPtr); + auto toDeadline = [](quint32 lifetime) -> QDeadlineTimer { + if (lifetime == quint32(-1)) + return QDeadlineTimer::Forever; + return QDeadlineTimer(lifetime * 1000); + }; + entry.setAddressLifetime(toDeadline(cacheinfo->ifa_prefered), toDeadline(cacheinfo->ifa_valid)); + } + break; + + case IFA_FLAGS: + Q_ASSERT(payloadLen == 4); + flags = qFromUnaligned<quint32>(payloadPtr); + break; + } + } + + // now handle flags + QNetworkInterfacePrivate::calculateDnsEligibility(&entry, + flags & IFA_F_TEMPORARY, + flags & IFA_F_DEPRECATED); + + + if (!entry.ip().isNull()) { + entry.setPrefixLength(ifa->ifa_prefixlen); + iface->addressEntries.append(entry); + } + }); +} + +QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan() +{ + // open netlink socket + QList<QNetworkInterfacePrivate *> result; + NetlinkSocket sock(BufferSize); + if (Q_UNLIKELY(sock == -1)) + return result; + + QByteArray buffer(BufferSize, Qt::Uninitialized); + char *buf = buffer.data(); + + result = getInterfaces(sock, buf); + getAddresses(sock, buf, result); + + return result; +} + +QT_END_NAMESPACE diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h index 51901eeda8..87a46b75fa 100644 --- a/src/network/kernel/qnetworkinterface_p.h +++ b/src/network/kernel/qnetworkinterface_p.h @@ -52,7 +52,9 @@ // #include <QtNetwork/private/qtnetworkglobal_p.h> +#include <QtNetwork/qnetworkinterface.h> #include <QtCore/qatomic.h> +#include <QtCore/qdeadlinetimer.h> #include <QtCore/qlist.h> #include <QtCore/qreadwritelock.h> #include <QtCore/qstring.h> @@ -69,7 +71,12 @@ class QNetworkAddressEntryPrivate public: QHostAddress address; QHostAddress broadcast; + QDeadlineTimer preferredLifetime = QDeadlineTimer::Forever; + QDeadlineTimer validityLifetime = QDeadlineTimer::Forever; + QNetmask netmask; + bool lifetimeKnown = false; + QNetworkAddressEntry::DnsEligibilityStatus dnsEligibility = QNetworkAddressEntry::DnsEligibilityUnknown; }; class QNetworkInterfacePrivate: public QSharedData @@ -81,7 +88,9 @@ public: { } int index; // interface index, if know + int mtu = 0; QNetworkInterface::InterfaceFlags flags; + QNetworkInterface::InterfaceType type = QNetworkInterface::Unknown; QString name; QString friendlyName; @@ -90,6 +99,20 @@ public: QList<QNetworkAddressEntry> addressEntries; static QString makeHwAddress(int len, uchar *data); + static void calculateDnsEligibility(QNetworkAddressEntry *entry, bool isTemporary, + bool isDeprecated) + { + // this implements an algorithm that yields the same results as Windows + // produces, for the same input (as far as I can test) + if (isTemporary || isDeprecated) + entry->setDnsEligibility(QNetworkAddressEntry::DnsIneligible); + + AddressClassification cl = QHostAddressPrivate::classify(entry->ip()); + if (cl == LoopbackAddress || cl == LinkLocalAddress) + entry->setDnsEligibility(QNetworkAddressEntry::DnsIneligible); + else + entry->setDnsEligibility(QNetworkAddressEntry::DnsEligible); + } private: // disallow copying -- avoid detaching diff --git a/src/network/kernel/qnetworkinterface_uikit_p.h b/src/network/kernel/qnetworkinterface_uikit_p.h new file mode 100644 index 0000000000..ea40e74f5c --- /dev/null +++ b/src/network/kernel/qnetworkinterface_uikit_p.h @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QNETWORKINTERFACE_UIKIT_P_H +#define QNETWORKINTERFACE_UIKIT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// Platform SDK for iOS, tvOS and watchOS is missing those headers: +// net/if_media.h, netinet/in_var.h, netinet6/in6_var.h This header is +// a workaround, it provides missing macros and structs. + +// <net/if_media.h>: + +/* + * Ethernet + */ +#define IFM_ETHER 0x00000020 +/* + * FDDI + */ +#define IFM_FDDI 0x00000060 +/* + * IEEE 802.11 Wireless + */ +#define IFM_IEEE80211 0x00000080 +/* + * Masks + */ +#define IFM_NMASK 0x000000e0 /* Network type */ +/* + * Macros to extract various bits of information from the media word. + */ +#define IFM_TYPE(x) ((x) & IFM_NMASK) + +// <netinet6/in6_var.h>: + +struct in6_addrlifetime { + time_t ia6t_expire; /* valid lifetime expiration time */ + time_t ia6t_preferred; /* preferred lifetime expiration time */ + u_int32_t ia6t_vltime; /* valid lifetime */ + u_int32_t ia6t_pltime; /* prefix lifetime */ +}; + +/* + * IPv6 interface statistics, as defined in RFC2465 Ipv6IfStatsEntry (p12). + */ +struct in6_ifstat { + u_quad_t ifs6_in_receive; /* # of total input datagram */ + u_quad_t ifs6_in_hdrerr; /* # of datagrams with invalid hdr */ + u_quad_t ifs6_in_toobig; /* # of datagrams exceeded MTU */ + u_quad_t ifs6_in_noroute; /* # of datagrams with no route */ + u_quad_t ifs6_in_addrerr; /* # of datagrams with invalid dst */ + u_quad_t ifs6_in_protounknown; /* # of datagrams with unknown proto */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_truncated; /* # of truncated datagrams */ + u_quad_t ifs6_in_discard; /* # of discarded datagrams */ + /* NOTE: fragment timeout is not here */ + u_quad_t ifs6_in_deliver; /* # of datagrams delivered to ULP */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_out_forward; /* # of datagrams forwarded */ + /* NOTE: increment on outgoing if */ + u_quad_t ifs6_out_request; /* # of outgoing datagrams from ULP */ + /* NOTE: does not include forwrads */ + u_quad_t ifs6_out_discard; /* # of discarded datagrams */ + u_quad_t ifs6_out_fragok; /* # of datagrams fragmented */ + u_quad_t ifs6_out_fragfail; /* # of datagrams failed on fragment */ + u_quad_t ifs6_out_fragcreat; /* # of fragment datagrams */ + /* NOTE: this is # after fragment */ + u_quad_t ifs6_reass_reqd; /* # of incoming fragmented packets */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_reass_ok; /* # of reassembled packets */ + /* NOTE: this is # after reass */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_atmfrag_rcvd; /* # of atomic fragments received */ + u_quad_t ifs6_reass_fail; /* # of reass failures */ + /* NOTE: may not be packet count */ + /* NOTE: increment on final dst if */ + u_quad_t ifs6_in_mcast; /* # of inbound multicast datagrams */ + u_quad_t ifs6_out_mcast; /* # of outbound multicast datagrams */ + + u_quad_t ifs6_cantfoward_icmp6; /* # of ICMPv6 packets received for unreachable dest */ + u_quad_t ifs6_addr_expiry_cnt; /* # of address expiry events (excluding privacy addresses) */ + u_quad_t ifs6_pfx_expiry_cnt; /* # of prefix expiry events */ + u_quad_t ifs6_defrtr_expiry_cnt; /* # of default router expiry events */ +}; + +/* + * ICMPv6 interface statistics, as defined in RFC2466 Ipv6IfIcmpEntry. + * XXX: I'm not sure if this file is the right place for this structure... + */ +struct icmp6_ifstat { + /* + * Input statistics + */ + /* ipv6IfIcmpInMsgs, total # of input messages */ + u_quad_t ifs6_in_msg; + /* ipv6IfIcmpInErrors, # of input error messages */ + u_quad_t ifs6_in_error; + /* ipv6IfIcmpInDestUnreachs, # of input dest unreach errors */ + u_quad_t ifs6_in_dstunreach; + /* ipv6IfIcmpInAdminProhibs, # of input admin. prohibited errs */ + u_quad_t ifs6_in_adminprohib; + /* ipv6IfIcmpInTimeExcds, # of input time exceeded errors */ + u_quad_t ifs6_in_timeexceed; + /* ipv6IfIcmpInParmProblems, # of input parameter problem errors */ + u_quad_t ifs6_in_paramprob; + /* ipv6IfIcmpInPktTooBigs, # of input packet too big errors */ + u_quad_t ifs6_in_pkttoobig; + /* ipv6IfIcmpInEchos, # of input echo requests */ + u_quad_t ifs6_in_echo; + /* ipv6IfIcmpInEchoReplies, # of input echo replies */ + u_quad_t ifs6_in_echoreply; + /* ipv6IfIcmpInRouterSolicits, # of input router solicitations */ + u_quad_t ifs6_in_routersolicit; + /* ipv6IfIcmpInRouterAdvertisements, # of input router advertisements */ + u_quad_t ifs6_in_routeradvert; + /* ipv6IfIcmpInNeighborSolicits, # of input neighbor solicitations */ + u_quad_t ifs6_in_neighborsolicit; + /* ipv6IfIcmpInNeighborAdvertisements, # of input neighbor advs. */ + u_quad_t ifs6_in_neighboradvert; + /* ipv6IfIcmpInRedirects, # of input redirects */ + u_quad_t ifs6_in_redirect; + /* ipv6IfIcmpInGroupMembQueries, # of input MLD queries */ + u_quad_t ifs6_in_mldquery; + /* ipv6IfIcmpInGroupMembResponses, # of input MLD reports */ + u_quad_t ifs6_in_mldreport; + /* ipv6IfIcmpInGroupMembReductions, # of input MLD done */ + u_quad_t ifs6_in_mlddone; + + /* + * Output statistics. We should solve unresolved routing problem... + */ + /* ipv6IfIcmpOutMsgs, total # of output messages */ + u_quad_t ifs6_out_msg; + /* ipv6IfIcmpOutErrors, # of output error messages */ + u_quad_t ifs6_out_error; + /* ipv6IfIcmpOutDestUnreachs, # of output dest unreach errors */ + u_quad_t ifs6_out_dstunreach; + /* ipv6IfIcmpOutAdminProhibs, # of output admin. prohibited errs */ + u_quad_t ifs6_out_adminprohib; + /* ipv6IfIcmpOutTimeExcds, # of output time exceeded errors */ + u_quad_t ifs6_out_timeexceed; + /* ipv6IfIcmpOutParmProblems, # of output parameter problem errors */ + u_quad_t ifs6_out_paramprob; + /* ipv6IfIcmpOutPktTooBigs, # of output packet too big errors */ + u_quad_t ifs6_out_pkttoobig; + /* ipv6IfIcmpOutEchos, # of output echo requests */ + u_quad_t ifs6_out_echo; + /* ipv6IfIcmpOutEchoReplies, # of output echo replies */ + u_quad_t ifs6_out_echoreply; + /* ipv6IfIcmpOutRouterSolicits, # of output router solicitations */ + u_quad_t ifs6_out_routersolicit; + /* ipv6IfIcmpOutRouterAdvertisements, # of output router advs. */ + u_quad_t ifs6_out_routeradvert; + /* ipv6IfIcmpOutNeighborSolicits, # of output neighbor solicitations */ + u_quad_t ifs6_out_neighborsolicit; + /* ipv6IfIcmpOutNeighborAdvertisements, # of output neighbor advs. */ + u_quad_t ifs6_out_neighboradvert; + /* ipv6IfIcmpOutRedirects, # of output redirects */ + u_quad_t ifs6_out_redirect; + /* ipv6IfIcmpOutGroupMembQueries, # of output MLD queries */ + u_quad_t ifs6_out_mldquery; + /* ipv6IfIcmpOutGroupMembResponses, # of output MLD reports */ + u_quad_t ifs6_out_mldreport; + /* ipv6IfIcmpOutGroupMembReductions, # of output MLD done */ + u_quad_t ifs6_out_mlddone; +}; + +#define SCOPE6_ID_MAX 16 + +struct in6_ifreq { + char ifr_name[IFNAMSIZ]; + union { + struct sockaddr_in6 ifru_addr; + struct sockaddr_in6 ifru_dstaddr; + int ifru_flags; + int ifru_flags6; + int ifru_metric; + int ifru_intval; + caddr_t ifru_data; + struct in6_addrlifetime ifru_lifetime; + struct in6_ifstat ifru_stat; + struct icmp6_ifstat ifru_icmp6stat; + u_int32_t ifru_scope_id[SCOPE6_ID_MAX]; + } ifr_ifru; +}; + +#define IN6_IFF_TEMPORARY 0x0080 /* temporary (anonymous) address. */ +#define IN6_IFF_DEPRECATED 0x0010 /* deprecated address */ + +#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq) +#define SIOCGIFALIFETIME_IN6 _IOWR('i', 81, struct in6_ifreq) + +// The definition below is ONLY a temporary workaround to unblock +// integrations on CI. MUST be removed ASAP, as soon as SDK is +// updated. Currently, we have WatchOS SDK 3.2 and it's missing +// net/if_types.h (unlike SDK 4.0, which has it). Alas, we have to +// work this around. We only define constants that we use in code. + +#if !QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, __IPHONE_NA, __TVOS_NA, __WATCHOS_4_0) + +#define QT_WATCHOS_OUTDATED_SDK_WORKAROUND + +#define IFT_PPP 0x17 /* RFC 1331 */ +#define IFT_LOOP 0x18 /* loopback */ +#define IFT_SLIP 0x1c /* IP over generic TTY */ + +#define IFT_GIF 0x37 /*0xf0*/ +#define IFT_STF 0x39 /*0xf3*/ + +#define IFT_IEEE1394 0x90 /* IEEE1394 High Performance SerialBus*/ + +#endif // WatchOS SDK below 4.0 + +#endif // QNETWORKINTERFACE_UIKIT_P_H + diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp index afa6b4296e..d69fc47667 100644 --- a/src/network/kernel/qnetworkinterface_unix.cpp +++ b/src/network/kernel/qnetworkinterface_unix.cpp @@ -41,30 +41,19 @@ #include "qset.h" #include "qnetworkinterface.h" #include "qnetworkinterface_p.h" +#include "qnetworkinterface_unix_p.h" #include "qalgorithms.h" -#include "private/qnet_unix_p.h" #ifndef QT_NO_NETWORKINTERFACE -#define IP_MULTICAST // make AIX happy and define IFF_MULTICAST - -#include <sys/types.h> -#include <sys/socket.h> - -#ifdef Q_OS_SOLARIS -# include <sys/sockio.h> +#if defined(QT_NO_CLOCK_MONOTONIC) +# include "qdatetime.h" #endif -#include <net/if.h> #if defined(QT_LINUXBASE) # define QT_NO_GETIFADDRS #endif -#ifdef Q_OS_HAIKU -# include <sys/sockio.h> -# define IFF_RUNNING 0x0001 -#endif - #ifndef QT_NO_GETIFADDRS # include <ifaddrs.h> #endif @@ -103,23 +92,6 @@ static QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex = 0, const QSt } -static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags) -{ - QNetworkInterface::InterfaceFlags flags = 0; - flags |= (rawFlags & IFF_UP) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0); - flags |= (rawFlags & IFF_RUNNING) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0); - flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0); - flags |= (rawFlags & IFF_LOOPBACK) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0); -#ifdef IFF_POINTOPOINT //cygwin doesn't define IFF_POINTOPOINT - flags |= (rawFlags & IFF_POINTOPOINT) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0); -#endif - -#ifdef IFF_MULTICAST - flags |= (rawFlags & IFF_MULTICAST) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0); -#endif - return flags; -} - uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name) { #ifndef QT_NO_IPV6IFNAME @@ -167,6 +139,15 @@ QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) return QString::number(uint(index)); } +static int getMtu(int socket, struct ifreq *req) +{ +#ifdef SIOCGIFMTU + if (qt_safe_ioctl(socket, SIOCGIFMTU, req) == 0) + return req->ifr_mtu; +#endif + return 0; +} + #ifdef QT_NO_GETIFADDRS // getifaddrs not available @@ -306,6 +287,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() if (qt_safe_ioctl(socket, SIOCGIFFLAGS, &req) >= 0) { iface->flags = convertFlags(req.ifr_flags); } + iface->mtu = getMtu(socket, &req); #ifdef SIOCGIFHWADDR // Get the HW address @@ -359,6 +341,7 @@ QT_END_INCLUDE_NAMESPACE static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) { + Q_UNUSED(getMtu) QList<QNetworkInterfacePrivate *> interfaces; QSet<QString> seenInterfaces; QVarLengthArray<int, 16> seenIndexes; // faster than QSet<int> @@ -413,14 +396,96 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) return interfaces; } +static void getAddressExtraInfo(QNetworkAddressEntry *entry, struct sockaddr *sa, const char *ifname) +{ + Q_UNUSED(entry); + Q_UNUSED(sa); + Q_UNUSED(ifname) +} + # elif defined(Q_OS_BSD4) QT_BEGIN_INCLUDE_NAMESPACE # include <net/if_dl.h> +#if defined(QT_PLATFORM_UIKIT) +# include "qnetworkinterface_uikit_p.h" +#if !defined(QT_WATCHOS_OUTDATED_SDK_WORKAROUND) +// TODO: remove it as soon as SDK is updated on CI!!! +# include <net/if_types.h> +#endif +#else +# include <net/if_media.h> +# include <net/if_types.h> +# include <netinet/in_var.h> +#endif // QT_PLATFORM_UIKIT QT_END_INCLUDE_NAMESPACE +static int openSocket(int &socket) +{ + if (socket == -1) + socket = qt_safe_socket(AF_INET, SOCK_DGRAM, 0); + return socket; +} + +static QNetworkInterface::InterfaceType probeIfType(int socket, int iftype, struct ifmediareq *req) +{ + // Determine the interface type. + + // On Darwin, these are #defines, but on FreeBSD they're just an + // enum, so we can't #ifdef them. Use the authoritative list from + // https://www.iana.org/assignments/smi-numbers/smi-numbers.xhtml#smi-numbers-5 + switch (iftype) { + case IFT_PPP: + return QNetworkInterface::Ppp; + + case IFT_LOOP: + return QNetworkInterface::Loopback; + + case IFT_SLIP: + return QNetworkInterface::Slip; + + case 0x47: // IFT_IEEE80211 + return QNetworkInterface::Ieee80211; + + case IFT_IEEE1394: + return QNetworkInterface::Ieee1394; + + case IFT_GIF: + case IFT_STF: + return QNetworkInterface::Virtual; + } + + // For the remainder (including Ethernet), let's try SIOGIFMEDIA + req->ifm_count = 0; + if (qt_safe_ioctl(socket, SIOCGIFMEDIA, req) == 0) { + // see https://man.openbsd.org/ifmedia.4 + + switch (IFM_TYPE(req->ifm_current)) { + case IFM_ETHER: + return QNetworkInterface::Ethernet; + + case IFM_FDDI: + return QNetworkInterface::Fddi; + + case IFM_IEEE80211: + return QNetworkInterface::Ieee80211; + } + } + + return QNetworkInterface::Unknown; +} + static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) { QList<QNetworkInterfacePrivate *> interfaces; + union { + struct ifmediareq mediareq; + struct ifreq req; + }; + int socket = -1; + + // ensure both structs start with the name field, of size IFNAMESIZ + Q_STATIC_ASSERT(sizeof(mediareq.ifm_name) == sizeof(req.ifr_name)); + Q_ASSERT(&mediareq.ifm_name == &req.ifr_name); // on NetBSD we use AF_LINK and sockaddr_dl // scan the list for that family @@ -434,15 +499,73 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) iface->name = QString::fromLatin1(ptr->ifa_name); iface->flags = convertFlags(ptr->ifa_flags); iface->hardwareAddress = iface->makeHwAddress(sdl->sdl_alen, (uchar*)LLADDR(sdl)); + + strlcpy(mediareq.ifm_name, ptr->ifa_name, sizeof(mediareq.ifm_name)); + iface->type = probeIfType(openSocket(socket), sdl->sdl_type, &mediareq); + iface->mtu = getMtu(socket, &req); } + if (socket != -1) + qt_safe_close(socket); return interfaces; } +static void getAddressExtraInfo(QNetworkAddressEntry *entry, struct sockaddr *sa, const char *ifname) +{ + // get IPv6 address lifetimes + if (sa->sa_family != AF_INET6) + return; + + struct in6_ifreq ifr; + + int s6 = qt_safe_socket(AF_INET6, SOCK_DGRAM, 0); + if (Q_UNLIKELY(s6 < 0)) { + qErrnoWarning("QNetworkInterface: could not create IPv6 socket"); + return; + } + + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + // get flags + ifr.ifr_addr = *reinterpret_cast<struct sockaddr_in6 *>(sa); + if (qt_safe_ioctl(s6, SIOCGIFAFLAG_IN6, &ifr) < 0) { + qt_safe_close(s6); + return; + } + int flags = ifr.ifr_ifru.ifru_flags6; + QNetworkInterfacePrivate::calculateDnsEligibility(entry, + flags & IN6_IFF_TEMPORARY, + flags & IN6_IFF_DEPRECATED); + + // get lifetimes + ifr.ifr_addr = *reinterpret_cast<struct sockaddr_in6 *>(sa); + if (qt_safe_ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr) < 0) { + qt_safe_close(s6); + return; + } + qt_safe_close(s6); + + auto toDeadline = [](time_t when) { + QDeadlineTimer deadline = QDeadlineTimer::Forever; + if (when) { +#if defined(QT_NO_CLOCK_MONOTONIC) + // no monotonic clock + deadline.setPreciseRemainingTime(when - QDateTime::currentSecsSinceEpoch()); +#else + deadline.setPreciseDeadline(when); +#endif + } + return deadline; + }; + entry->setAddressLifetime(toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_preferred), + toDeadline(ifr.ifr_ifru.ifru_lifetime.ia6t_expire)); +} + # else // Generic version static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) { + Q_UNUSED(getMtu) QList<QNetworkInterfacePrivate *> interfaces; // make sure there's one entry for each interface @@ -470,9 +593,14 @@ static QList<QNetworkInterfacePrivate *> createInterfaces(ifaddrs *rawList) return interfaces; } +static void getAddressExtraInfo(QNetworkAddressEntry *entry, struct sockaddr *sa, const char *ifname) +{ + Q_UNUSED(entry); + Q_UNUSED(sa); + Q_UNUSED(ifname) +} # endif - static QList<QNetworkInterfacePrivate *> interfaceListing() { QList<QNetworkInterfacePrivate *> interfaces; @@ -521,6 +649,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() entry.setNetmask(addressFromSockaddr(ptr->ifa_netmask, iface->index, iface->name)); if (iface->flags & QNetworkInterface::CanBroadcast) entry.setBroadcast(addressFromSockaddr(ptr->ifa_broadaddr, iface->index, iface->name)); + getAddressExtraInfo(&entry, ptr->ifa_addr, name.latin1()); iface->addressEntries << entry; } diff --git a/src/network/kernel/qnetworkinterface_unix_p.h b/src/network/kernel/qnetworkinterface_unix_p.h new file mode 100644 index 0000000000..c085194e3c --- /dev/null +++ b/src/network/kernel/qnetworkinterface_unix_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2017 Intel Corporation. +** 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 QNETWORKINTERFACE_UNIX_P_H +#define QNETWORKINTERFACE_UNIX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qnetworkinterface_p.h" +#include "private/qnet_unix_p.h" + +#ifndef QT_NO_NETWORKINTERFACE + +#define IP_MULTICAST // make AIX happy and define IFF_MULTICAST + +#include <sys/types.h> +#include <sys/socket.h> +#ifdef Q_OS_SOLARIS +# include <sys/sockio.h> +#endif +#ifdef Q_OS_HAIKU +# include <sys/sockio.h> +# define IFF_RUNNING 0x0001 +#endif +#if QT_CONFIG(linux_netlink) +// Same as net/if.h but contains other things we need in +// qnetworkinterface_linux.cpp. +# include <linux/if.h> +#else +# include <net/if.h> +#endif + +QT_BEGIN_NAMESPACE + +static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags) +{ + QNetworkInterface::InterfaceFlags flags = 0; + flags |= (rawFlags & IFF_UP) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0); + flags |= (rawFlags & IFF_RUNNING) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0); + flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0); + flags |= (rawFlags & IFF_LOOPBACK) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0); +#ifdef IFF_POINTOPOINT //cygwin doesn't define IFF_POINTOPOINT + flags |= (rawFlags & IFF_POINTOPOINT) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0); +#endif + +#ifdef IFF_MULTICAST + flags |= (rawFlags & IFF_MULTICAST) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0); +#endif + return flags; +} + +QT_END_NAMESPACE + +#endif // QT_NO_NETWORKINTERFACE + +#endif // QNETWORKINTERFACE_UNIX_P_H diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp index 64c3fa6f83..150553f673 100644 --- a/src/network/kernel/qnetworkinterface_win.cpp +++ b/src/network/kernel/qnetworkinterface_win.cpp @@ -62,6 +62,10 @@ #include <qt_windows.h> +// In case these aren't defined +#define IF_TYPE_IEEE80216_WMAN 237 +#define IF_TYPE_IEEE802154 259 + QT_BEGIN_NAMESPACE static QHostAddress addressFromSockaddr(sockaddr *sa) @@ -147,6 +151,7 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() else if (ptr->IfIndex != 0) iface->index = ptr->IfIndex; + iface->mtu = qMin<qint64>(ptr->Mtu, INT_MAX); iface->flags = QNetworkInterface::CanBroadcast; if (ptr->OperStatus == IfOperStatusUp) iface->flags |= QNetworkInterface::IsUp | QNetworkInterface::IsRunning; @@ -155,6 +160,45 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() if (ptr->IfType == IF_TYPE_PPP) iface->flags |= QNetworkInterface::IsPointToPoint; + switch (ptr->IfType) { + case IF_TYPE_ETHERNET_CSMACD: + iface->type = QNetworkInterface::Ethernet; + break; + + case IF_TYPE_FDDI: + iface->type = QNetworkInterface::Fddi; + break; + + case IF_TYPE_PPP: + iface->type = QNetworkInterface::Ppp; + break; + + case IF_TYPE_SLIP: + iface->type = QNetworkInterface::Slip; + break; + + case IF_TYPE_SOFTWARE_LOOPBACK: + iface->type = QNetworkInterface::Loopback; + iface->flags |= QNetworkInterface::IsLoopBack; + break; + + case IF_TYPE_IEEE80211: + iface->type = QNetworkInterface::Ieee80211; + break; + + case IF_TYPE_IEEE1394: + iface->type = QNetworkInterface::Ieee1394; + break; + + case IF_TYPE_IEEE80216_WMAN: + iface->type = QNetworkInterface::Ieee80216; + break; + + case IF_TYPE_IEEE802154: + iface->type = QNetworkInterface::Ieee802154; + break; + } + // use ConvertInterfaceLuidToNameW because that returns a friendlier name, though not // as "friendly" as FriendlyName below WCHAR buf[IF_MAX_STRING_SIZE + 1]; @@ -167,9 +211,6 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() if (ptr->PhysicalAddressLength) iface->hardwareAddress = iface->makeHwAddress(ptr->PhysicalAddressLength, ptr->PhysicalAddress); - else - // loopback if it has no address - iface->flags |= QNetworkInterface::IsLoopBack; // parse the IP (unicast) addresses for (PIP_ADAPTER_UNICAST_ADDRESS addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) { @@ -182,6 +223,17 @@ static QList<QNetworkInterfacePrivate *> interfaceListing() QNetworkAddressEntry entry; entry.setIp(addressFromSockaddr(addr->Address.lpSockaddr)); entry.setPrefixLength(addr->OnLinkPrefixLength); + + auto toDeadline = [](ULONG lifetime) -> QDeadlineTimer { + if (lifetime == 0xffffffffUL) + return QDeadlineTimer::Forever; + return QDeadlineTimer(lifetime * 1000); + }; + entry.setAddressLifetime(toDeadline(addr->ValidLifetime), toDeadline(addr->PreferredLifetime)); + entry.setDnsEligibility(addr->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE ? + QNetworkAddressEntry::DnsEligible : + QNetworkAddressEntry::DnsIneligible); + iface->addressEntries << entry; } } diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index 6b53b4b58e..3646a9526a 100644 --- a/src/network/kernel/qnetworkproxy.cpp +++ b/src/network/kernel/qnetworkproxy.cpp @@ -230,7 +230,11 @@ #if QT_CONFIG(socks5) #include "private/qsocks5socketengine_p.h" #endif + +#if QT_CONFIG(http) #include "private/qhttpsocketengine_p.h" +#endif + #include "qauthenticator.h" #include "qdebug.h" #include "qmutex.h" @@ -256,7 +260,7 @@ public: #if QT_CONFIG(socks5) , socks5SocketEngineHandler(0) #endif -#ifndef QT_NO_HTTP +#if QT_CONFIG(http) , httpSocketEngineHandler(0) #endif #ifdef QT_USE_SYSTEM_PROXIES @@ -268,7 +272,7 @@ public: #if QT_CONFIG(socks5) socks5SocketEngineHandler = new QSocks5SocketEngineHandler(); #endif -#ifndef QT_NO_HTTP +#if QT_CONFIG(http) httpSocketEngineHandler = new QHttpSocketEngineHandler(); #endif } @@ -280,7 +284,7 @@ public: #if QT_CONFIG(socks5) delete socks5SocketEngineHandler; #endif -#ifndef QT_NO_HTTP +#if QT_CONFIG(http) delete httpSocketEngineHandler; #endif } @@ -340,7 +344,7 @@ private: #if QT_CONFIG(socks5) QSocks5SocketEngineHandler *socks5SocketEngineHandler; #endif -#ifndef QT_NO_HTTP +#if QT_CONFIG(http) QHttpSocketEngineHandler *httpSocketEngineHandler; #endif bool useSystemProxies; diff --git a/src/network/network.pro b/src/network/network.pro index 98fbf82275..b8272d91d6 100644 --- a/src/network/network.pro +++ b/src/network/network.pro @@ -24,8 +24,6 @@ QMAKE_LIBS += $$QMAKE_LIBS_NETWORK qtConfig(bearermanagement) { ANDROID_BUNDLED_JAR_DEPENDENCIES = \ - jar/QtAndroidBearer-bundled.jar - ANDROID_JAR_DEPENDENCIES = \ jar/QtAndroidBearer.jar ANDROID_LIB_DEPENDENCIES = \ plugins/bearer/libqandroidbearer.so diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index ec88851589..13e10e4102 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -387,6 +387,11 @@ (see \l{QAbstractSocket::}{setReadBufferSize()}). This enum value has been introduced in Qt 5.3. + \value PathMtuSocketOption Retrieves the Path Maximum Transmission Unit + (PMTU) value currently known by the IP stack, if any. Some IP stacks also + allow setting the MTU for transmission. + This enum value was introduced in Qt 5.11. + Possible values for \e{TypeOfServiceOption} are: \table @@ -1354,15 +1359,29 @@ void QAbstractSocketPrivate::fetchConnectionParameters() } state = QAbstractSocket::ConnectedState; - emit q->stateChanged(state); - emit q->connected(); - #if defined(QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::fetchConnectionParameters() connection to %s:%i established", host.toString().toLatin1().constData(), port); #endif + emit q->stateChanged(state); + emit q->connected(); } +/*! \internal +*/ +qint64 QAbstractSocketPrivate::skip(qint64 maxSize) +{ + // if we're not connected, return -1 indicating EOF + if (!socketEngine || !socketEngine->isValid() || state != QAbstractSocket::ConnectedState) + return -1; + + // Caller, QIODevice::skip(), has ensured buffer is empty. So, wait + // for more data in buffered mode. + if (isBuffered) + return 0; + + return QIODevicePrivate::skip(maxSize); +} void QAbstractSocketPrivate::pauseSocketNotifiers(QAbstractSocket *socket) { @@ -2013,6 +2032,10 @@ void QAbstractSocket::setSocketOption(QAbstractSocket::SocketOption option, cons case ReceiveBufferSizeSocketOption: d_func()->socketEngine->setOption(QAbstractSocketEngine::ReceiveBufferSocketOption, value.toInt()); break; + + case PathMtuSocketOption: + d_func()->socketEngine->setOption(QAbstractSocketEngine::PathMtuInformation, value.toInt()); + break; } } @@ -2055,6 +2078,10 @@ QVariant QAbstractSocket::socketOption(QAbstractSocket::SocketOption option) case ReceiveBufferSizeSocketOption: ret = d_func()->socketEngine->option(QAbstractSocketEngine::ReceiveBufferSocketOption); break; + + case PathMtuSocketOption: + ret = d_func()->socketEngine->option(QAbstractSocketEngine::PathMtuInformation); + break; } if (ret == -1) return QVariant(); diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index 875609aa28..6d5e57ac52 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -120,7 +120,8 @@ public: MulticastLoopbackOption, // IP_MULTICAST_LOOPBACK TypeOfServiceOption, //IP_TOS SendBufferSizeSocketOption, //SO_SNDBUF - ReceiveBufferSizeSocketOption //SO_RCVBUF + ReceiveBufferSizeSocketOption, //SO_RCVBUF + PathMtuSocketOption // IP_MTU }; Q_ENUM(SocketOption) enum BindFlag { @@ -154,10 +155,10 @@ public: bool isValid() const; - qint64 bytesAvailable() const Q_DECL_OVERRIDE; - qint64 bytesToWrite() const Q_DECL_OVERRIDE; + qint64 bytesAvailable() const override; + qint64 bytesToWrite() const override; - bool canReadLine() const Q_DECL_OVERRIDE; // ### Qt6: remove me + bool canReadLine() const override; // ### Qt6: remove me quint16 localPort() const; QHostAddress localAddress() const; @@ -182,15 +183,15 @@ public: SocketError error() const; // from QIODevice - void close() Q_DECL_OVERRIDE; - bool isSequential() const Q_DECL_OVERRIDE; - bool atEnd() const Q_DECL_OVERRIDE; // ### Qt6: remove me + void close() override; + bool isSequential() const override; + bool atEnd() const override; // ### Qt6: remove me bool flush(); // for synchronous access virtual bool waitForConnected(int msecs = 30000); - bool waitForReadyRead(int msecs = 30000) Q_DECL_OVERRIDE; - bool waitForBytesWritten(int msecs = 30000) Q_DECL_OVERRIDE; + bool waitForReadyRead(int msecs = 30000) override; + bool waitForBytesWritten(int msecs = 30000) override; virtual bool waitForDisconnected(int msecs = 30000); #ifndef QT_NO_NETWORKPROXY @@ -209,9 +210,9 @@ Q_SIGNALS: #endif protected: - qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 readLineData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE; + qint64 readData(char *data, qint64 maxlen) override; + qint64 readLineData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; void setSocketState(SocketState state); void setSocketError(SocketError socketError); @@ -221,7 +222,7 @@ protected: void setPeerAddress(const QHostAddress &address); void setPeerName(const QString &name); - QAbstractSocket(SocketType socketType, QAbstractSocketPrivate &dd, QObject *parent = Q_NULLPTR); + QAbstractSocket(SocketType socketType, QAbstractSocketPrivate &dd, QObject *parent = nullptr); private: Q_DECLARE_PRIVATE(QAbstractSocket) diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 3873b50864..066a35ff85 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -71,6 +71,9 @@ public: QAbstractSocketPrivate(); virtual ~QAbstractSocketPrivate(); + // from QIODevicePrivate + qint64 skip(qint64 maxSize) override; + // from QAbstractSocketEngineReceiver inline void readNotification() override { canReadNotification(); } inline void writeNotification() override { canWriteNotification(); } diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h index 0cb519ce90..b15dd73c96 100644 --- a/src/network/socket/qabstractsocketengine_p.h +++ b/src/network/socket/qabstractsocketengine_p.h @@ -105,7 +105,8 @@ public: TypeOfServiceOption, ReceivePacketInformation, ReceiveHopLimit, - MaxStreamsSocketOption + MaxStreamsSocketOption, + PathMtuInformation }; enum PacketHeaderOption { diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 899c02fba6..b543ea7981 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -46,7 +46,7 @@ #include "qelapsedtimer.h" #include "qnetworkinterface.h" -#if !defined(QT_NO_NETWORKPROXY) && !defined(QT_NO_HTTP) +#if !defined(QT_NO_NETWORKPROXY) #include <qdebug.h> QT_BEGIN_NAMESPACE @@ -572,18 +572,13 @@ void QHttpSocketEngine::slotSocketReadNotification() } if (d->state == ReadResponseContent) { - char dummybuffer[4096]; - while (d->pendingResponseData) { - int read = d->socket->read(dummybuffer, qMin(sizeof(dummybuffer), (size_t)d->pendingResponseData)); - if (read == 0) - return; - if (read == -1) { - d->socket->disconnectFromHost(); - emitWriteNotification(); - return; - } - d->pendingResponseData -= read; + qint64 skipped = d->socket->skip(d->pendingResponseData); + if (skipped == -1) { + d->socket->disconnectFromHost(); + emitWriteNotification(); + return; } + d->pendingResponseData -= uint(skipped); if (d->pendingResponseData > 0) return; if (d->reply->d_func()->statusCode == 407) @@ -871,4 +866,4 @@ QAbstractSocketEngine *QHttpSocketEngineHandler::createSocketEngine(qintptr, QOb QT_END_NAMESPACE -#endif +#endif // !QT_NO_NETWORKPROXY diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h index 07815a7e51..cb7798694a 100644 --- a/src/network/socket/qhttpsocketengine_p.h +++ b/src/network/socket/qhttpsocketengine_p.h @@ -57,9 +57,11 @@ #include "qnetworkproxy.h" #include "private/qauthenticator_p.h" +QT_REQUIRE_CONFIG(http); + QT_BEGIN_NAMESPACE -#if !defined(QT_NO_NETWORKPROXY) && !defined(QT_NO_HTTP) +#if !defined(QT_NO_NETWORKPROXY) class QTcpSocket; class QHttpNetworkReply; @@ -80,62 +82,62 @@ public: QHttpSocketEngine(QObject *parent = 0); ~QHttpSocketEngine(); - bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) Q_DECL_OVERRIDE; - bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) Q_DECL_OVERRIDE; + bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override; + bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) override; void setProxy(const QNetworkProxy &networkProxy); - qintptr socketDescriptor() const Q_DECL_OVERRIDE; + qintptr socketDescriptor() const override; - bool isValid() const Q_DECL_OVERRIDE; + bool isValid() const override; bool connectInternal(); - bool connectToHost(const QHostAddress &address, quint16 port) Q_DECL_OVERRIDE; - bool connectToHostByName(const QString &name, quint16 port) Q_DECL_OVERRIDE; - bool bind(const QHostAddress &address, quint16 port) Q_DECL_OVERRIDE; - bool listen() Q_DECL_OVERRIDE; - int accept() Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; + bool connectToHost(const QHostAddress &address, quint16 port) override; + bool connectToHostByName(const QString &name, quint16 port) override; + bool bind(const QHostAddress &address, quint16 port) override; + bool listen() override; + int accept() override; + void close() override; - qint64 bytesAvailable() const Q_DECL_OVERRIDE; + qint64 bytesAvailable() const override; - qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; + qint64 read(char *data, qint64 maxlen) override; + qint64 write(const char *data, qint64 len) override; #ifndef QT_NO_UDPSOCKET #ifndef QT_NO_NETWORKINTERFACE bool joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) Q_DECL_OVERRIDE; + const QNetworkInterface &interface) override; bool leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) Q_DECL_OVERRIDE; - QNetworkInterface multicastInterface() const Q_DECL_OVERRIDE; - bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE; + const QNetworkInterface &interface) override; + QNetworkInterface multicastInterface() const override; + bool setMulticastInterface(const QNetworkInterface &iface) override; #endif // QT_NO_NETWORKINTERFACE - bool hasPendingDatagrams() const Q_DECL_OVERRIDE; - qint64 pendingDatagramSize() const Q_DECL_OVERRIDE; + bool hasPendingDatagrams() const override; + qint64 pendingDatagramSize() const override; #endif // QT_NO_UDPSOCKET qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *, - PacketHeaderOptions) Q_DECL_OVERRIDE; - qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE; - qint64 bytesToWrite() const Q_DECL_OVERRIDE; + PacketHeaderOptions) override; + qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) override; + qint64 bytesToWrite() const override; - int option(SocketOption option) const Q_DECL_OVERRIDE; - bool setOption(SocketOption option, int value) Q_DECL_OVERRIDE; + int option(SocketOption option) const override; + bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; - bool waitForWrite(int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; + bool waitForRead(int msecs = 30000, bool *timedOut = 0) override; + bool waitForWrite(int msecs = 30000, bool *timedOut = 0) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; + int msecs = 30000, bool *timedOut = 0) override; - bool isReadNotificationEnabled() const Q_DECL_OVERRIDE; - void setReadNotificationEnabled(bool enable) Q_DECL_OVERRIDE; - bool isWriteNotificationEnabled() const Q_DECL_OVERRIDE; - void setWriteNotificationEnabled(bool enable) Q_DECL_OVERRIDE; - bool isExceptionNotificationEnabled() const Q_DECL_OVERRIDE; - void setExceptionNotificationEnabled(bool enable) Q_DECL_OVERRIDE; + bool isReadNotificationEnabled() const override; + void setReadNotificationEnabled(bool enable) override; + bool isWriteNotificationEnabled() const override; + void setWriteNotificationEnabled(bool enable) override; + bool isExceptionNotificationEnabled() const override; + void setExceptionNotificationEnabled(bool enable) override; public slots: void slotSocketConnected(); @@ -190,8 +192,8 @@ class Q_AUTOTEST_EXPORT QHttpSocketEngineHandler : public QSocketEngineHandler { public: virtual QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType, - const QNetworkProxy &, QObject *parent) Q_DECL_OVERRIDE; - virtual QAbstractSocketEngine *createSocketEngine(qintptr socketDescripter, QObject *parent) Q_DECL_OVERRIDE; + const QNetworkProxy &, QObject *parent) override; + virtual QAbstractSocketEngine *createSocketEngine(qintptr socketDescripter, QObject *parent) override; }; #endif diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h index 454ac30c9b..211aa94d85 100644 --- a/src/network/socket/qlocalserver.h +++ b/src/network/socket/qlocalserver.h @@ -71,7 +71,7 @@ public: Q_DECLARE_FLAGS(SocketOptions, SocketOption) Q_FLAG(SocketOptions) - explicit QLocalServer(QObject *parent = Q_NULLPTR); + explicit QLocalServer(QObject *parent = nullptr); ~QLocalServer(); void close(); @@ -87,7 +87,7 @@ public: static bool removeServer(const QString &name); QAbstractSocket::SocketError serverError() const; void setMaxPendingConnections(int numConnections); - bool waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR); + bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr); void setSocketOptions(SocketOptions options); SocketOptions socketOptions() const; diff --git a/src/network/socket/qlocalsocket.h b/src/network/socket/qlocalsocket.h index 9905d3a86c..1876a6ac0d 100644 --- a/src/network/socket/qlocalsocket.h +++ b/src/network/socket/qlocalsocket.h @@ -79,7 +79,7 @@ public: ClosingState = QAbstractSocket::ClosingState }; - QLocalSocket(QObject *parent = Q_NULLPTR); + QLocalSocket(QObject *parent = nullptr); ~QLocalSocket(); void connectToServer(OpenMode openMode = ReadWrite); @@ -91,12 +91,12 @@ public: QString fullServerName() const; void abort(); - virtual bool isSequential() const Q_DECL_OVERRIDE; - virtual qint64 bytesAvailable() const Q_DECL_OVERRIDE; - virtual qint64 bytesToWrite() const Q_DECL_OVERRIDE; - virtual bool canReadLine() const Q_DECL_OVERRIDE; - virtual bool open(OpenMode openMode = ReadWrite) Q_DECL_OVERRIDE; - virtual void close() Q_DECL_OVERRIDE; + virtual bool isSequential() const override; + virtual qint64 bytesAvailable() const override; + virtual qint64 bytesToWrite() const override; + virtual bool canReadLine() const override; + virtual bool open(OpenMode openMode = ReadWrite) override; + virtual void close() override; LocalSocketError error() const; bool flush(); bool isValid() const; @@ -109,10 +109,10 @@ public: qintptr socketDescriptor() const; LocalSocketState state() const; - bool waitForBytesWritten(int msecs = 30000) Q_DECL_OVERRIDE; + bool waitForBytesWritten(int msecs = 30000) override; bool waitForConnected(int msecs = 30000); bool waitForDisconnected(int msecs = 30000); - bool waitForReadyRead(int msecs = 30000) Q_DECL_OVERRIDE; + bool waitForReadyRead(int msecs = 30000) override; Q_SIGNALS: void connected(); @@ -121,8 +121,8 @@ Q_SIGNALS: void stateChanged(QLocalSocket::LocalSocketState socketState); protected: - virtual qint64 readData(char*, qint64) Q_DECL_OVERRIDE; - virtual qint64 writeData(const char*, qint64) Q_DECL_OVERRIDE; + virtual qint64 readData(char*, qint64) override; + virtual qint64 writeData(const char*, qint64) override; private: Q_DISABLE_COPY(QLocalSocket) diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h index eb59af5577..8b72da397f 100644 --- a/src/network/socket/qlocalsocket_p.h +++ b/src/network/socket/qlocalsocket_p.h @@ -120,6 +120,7 @@ public: void init(); #if defined(QT_LOCALSOCKET_TCP) + qint64 skip(qint64 maxSize) override; QLocalUnixSocket* tcpSocket; bool ownsTcpSocket; void setSocket(QLocalUnixSocket*); @@ -139,6 +140,7 @@ public: QWindowsPipeReader *pipeReader; QLocalSocket::LocalSocketError error; #else + qint64 skip(qint64 maxSize) override; QLocalUnixSocket unixSocket; QString generateErrorString(QLocalSocket::LocalSocketError, const QString &function) const; void errorOccurred(QLocalSocket::LocalSocketError, const QString &function); diff --git a/src/network/socket/qlocalsocket_tcp.cpp b/src/network/socket/qlocalsocket_tcp.cpp index 379cdd096d..41e5b47627 100644 --- a/src/network/socket/qlocalsocket_tcp.cpp +++ b/src/network/socket/qlocalsocket_tcp.cpp @@ -83,6 +83,11 @@ void QLocalSocketPrivate::setSocket(QLocalUnixSocket* socket) tcpSocket->setParent(q); } +qint64 QLocalSocketPrivate::skip(qint64 maxSize) +{ + return tcpSocket->skip(maxSize); +} + void QLocalSocketPrivate::_q_error(QAbstractSocket::SocketError socketError) { Q_Q(QLocalSocket); diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp index c1d79e8137..d1df26d9f1 100644 --- a/src/network/socket/qlocalsocket_unix.cpp +++ b/src/network/socket/qlocalsocket_unix.cpp @@ -88,6 +88,11 @@ void QLocalSocketPrivate::init() unixSocket.setParent(q); } +qint64 QLocalSocketPrivate::skip(qint64 maxSize) +{ + return unixSocket.skip(maxSize); +} + void QLocalSocketPrivate::_q_error(QAbstractSocket::SocketError socketError) { Q_Q(QLocalSocket); diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index d488ce150c..aa61b74823 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -128,43 +128,43 @@ public: QNativeSocketEngine(QObject *parent = 0); ~QNativeSocketEngine(); - bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) Q_DECL_OVERRIDE; - bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) Q_DECL_OVERRIDE; + bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override; + bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) override; - qintptr socketDescriptor() const Q_DECL_OVERRIDE; + qintptr socketDescriptor() const override; - bool isValid() const Q_DECL_OVERRIDE; + bool isValid() const override; - bool connectToHost(const QHostAddress &address, quint16 port) Q_DECL_OVERRIDE; - bool connectToHostByName(const QString &name, quint16 port) Q_DECL_OVERRIDE; - bool bind(const QHostAddress &address, quint16 port) Q_DECL_OVERRIDE; - bool listen() Q_DECL_OVERRIDE; - int accept() Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; + bool connectToHost(const QHostAddress &address, quint16 port) override; + bool connectToHostByName(const QString &name, quint16 port) override; + bool bind(const QHostAddress &address, quint16 port) override; + bool listen() override; + int accept() override; + void close() override; - qint64 bytesAvailable() const Q_DECL_OVERRIDE; + qint64 bytesAvailable() const override; - qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; + qint64 read(char *data, qint64 maxlen) override; + qint64 write(const char *data, qint64 len) override; #ifndef QT_NO_UDPSOCKET #ifndef QT_NO_NETWORKINTERFACE bool joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface) Q_DECL_OVERRIDE; + const QNetworkInterface &iface) override; bool leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface) Q_DECL_OVERRIDE; - QNetworkInterface multicastInterface() const Q_DECL_OVERRIDE; - bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE; + const QNetworkInterface &iface) override; + QNetworkInterface multicastInterface() const override; + bool setMulticastInterface(const QNetworkInterface &iface) override; #endif - bool hasPendingDatagrams() const Q_DECL_OVERRIDE; - qint64 pendingDatagramSize() const Q_DECL_OVERRIDE; + bool hasPendingDatagrams() const override; + qint64 pendingDatagramSize() const override; #endif // QT_NO_UDPSOCKET qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0, - PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE; - qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE; - qint64 bytesToWrite() const Q_DECL_OVERRIDE; + PacketHeaderOptions = WantNone) override; + qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) override; + qint64 bytesToWrite() const override; #if 0 // currently unused qint64 receiveBufferSize() const; @@ -174,21 +174,21 @@ public: void setSendBufferSize(qint64 bufferSize); #endif - int option(SocketOption option) const Q_DECL_OVERRIDE; - bool setOption(SocketOption option, int value) Q_DECL_OVERRIDE; + int option(SocketOption option) const override; + bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; - bool waitForWrite(int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; + bool waitForRead(int msecs = 30000, bool *timedOut = 0) override; + bool waitForWrite(int msecs = 30000, bool *timedOut = 0) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; - - bool isReadNotificationEnabled() const Q_DECL_OVERRIDE; - void setReadNotificationEnabled(bool enable) Q_DECL_OVERRIDE; - bool isWriteNotificationEnabled() const Q_DECL_OVERRIDE; - void setWriteNotificationEnabled(bool enable) Q_DECL_OVERRIDE; - bool isExceptionNotificationEnabled() const Q_DECL_OVERRIDE; - void setExceptionNotificationEnabled(bool enable) Q_DECL_OVERRIDE; + int msecs = 30000, bool *timedOut = 0) override; + + bool isReadNotificationEnabled() const override; + void setReadNotificationEnabled(bool enable) override; + bool isWriteNotificationEnabled() const override; + void setWriteNotificationEnabled(bool enable) override; + bool isExceptionNotificationEnabled() const override; + void setExceptionNotificationEnabled(bool enable) override; public Q_SLOTS: // non-virtual override; diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index cb0a521360..b380b0f7d6 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -226,6 +226,20 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, #endif } break; + + case QNativeSocketEngine::PathMtuInformation: + if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { +#ifdef IPV6_MTU + level = IPPROTO_IPV6; + n = IPV6_MTU; +#endif + } else { +#ifdef IP_MTU + level = IPPROTO_IP; + n = IP_MTU; +#endif + } + break; } } @@ -331,6 +345,20 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co return -1; } + case QNativeSocketEngine::PathMtuInformation: +#if defined(IPV6_PATHMTU) && !defined(IPV6_MTU) + // Prefer IPV6_MTU (handled by convertToLevelAndOption), if available + // (Linux); fall back to IPV6_PATHMTU otherwise (FreeBSD): + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + ip6_mtuinfo mtuinfo; + QT_SOCKOPTLEN_T len = sizeof(mtuinfo); + if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_PATHMTU, &mtuinfo, &len) == 0) + return int(mtuinfo.ip6m_mtu); + return -1; + } +#endif + break; + default: break; } @@ -420,6 +448,8 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt } #endif + if (n == -1) + return false; return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0; } diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 6a091209be..c303f01648 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -209,7 +209,7 @@ static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n) { - n = 0; + n = -1; level = SOL_SOCKET; // default switch (opt) { @@ -281,6 +281,9 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, n = IP_HOPLIMIT; } break; + + case QAbstractSocketEngine::PathMtuInformation: + break; // not supported on Windows } } @@ -471,9 +474,11 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co QT_SOCKOPTLEN_T len = sizeof(v); convertToLevelAndOption(opt, socketProtocol, level, n); - if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) == 0) - return v; - WS_ERROR_DEBUG(WSAGetLastError()); + if (n != -1) { + if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) == 0) + return v; + WS_ERROR_DEBUG(WSAGetLastError()); + } return -1; } @@ -491,9 +496,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt switch (opt) { case QNativeSocketEngine::SendBufferSocketOption: // see QTBUG-30478 SO_SNDBUF should not be used on Vista or later - if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) - return false; - break; + return false; case QNativeSocketEngine::NonBlockingSocketOption: { unsigned long buf = v; @@ -516,6 +519,8 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt int n, level; convertToLevelAndOption(opt, socketProtocol, level, n); + if (n == -1) + return false; if (::setsockopt(socketDescriptor, level, n, (char*)&v, sizeof(v)) != 0) { WS_ERROR_DEBUG(WSAGetLastError()); return false; @@ -571,7 +576,6 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() DWORD ipv6only = 0; QT_SOCKOPTLEN_T optlen = sizeof(ipv6only); if (localAddress == QHostAddress::AnyIPv6 - && QSysInfo::windowsVersion() >= QSysInfo::WV_6_0 && !getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, &optlen )) { if (!ipv6only) { socketProtocol = QAbstractSocket::AnyIPProtocol; @@ -632,10 +636,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin if ((socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) && address.toIPv4Address()) { //IPV6_V6ONLY option must be cleared to connect to a V4 mapped address - if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) { - DWORD ipv6only = 0; - ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); - } + DWORD ipv6only = 0; + ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); } forever { diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp index b7d7042923..9df5f0c500 100644 --- a/src/network/socket/qnativesocketengine_winrt.cpp +++ b/src/network/socket/qnativesocketengine_winrt.cpp @@ -1340,7 +1340,7 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() , closingDown(false) , socketDescriptor(-1) , worker(new SocketEngineWorker(this)) - , sslSocket(Q_NULLPTR) + , sslSocket(nullptr) , connectionToken( { -1 } ) { } @@ -1514,6 +1514,7 @@ int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt) case QAbstractSocketEngine::MulticastLoopbackOption: case QAbstractSocketEngine::TypeOfServiceOption: case QAbstractSocketEngine::MaxStreamsSocketOption: + case QAbstractSocketEngine::PathMtuInformation: default: return -1; } @@ -1573,6 +1574,7 @@ bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption o case QAbstractSocketEngine::MulticastLoopbackOption: case QAbstractSocketEngine::TypeOfServiceOption: case QAbstractSocketEngine::MaxStreamsSocketOption: + case QAbstractSocketEngine::PathMtuInformation: default: return false; } diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h index 5359872f96..e038352352 100644 --- a/src/network/socket/qnet_unix_p.h +++ b/src/network/socket/qnet_unix_p.h @@ -78,7 +78,6 @@ QT_BEGIN_NAMESPACE # define QT_SOCKOPTLEN_T QT_SOCKLEN_T #endif -// UnixWare 7 redefines socket -> _socket static inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0) { Q_ASSERT((flags & ~O_NONBLOCK) == 0); @@ -105,7 +104,6 @@ static inline int qt_safe_socket(int domain, int type, int protocol, int flags = #endif } -// Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDED static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen, int flags = 0) { Q_ASSERT((flags & ~O_NONBLOCK) == 0); @@ -137,7 +135,6 @@ static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *add #endif } -// UnixWare 7 redefines listen -> _listen static inline int qt_safe_listen(int s, int backlog) { return ::listen(s, backlog); diff --git a/src/network/socket/qsctpserver.h b/src/network/socket/qsctpserver.h index 1afdab28a0..b678ba053d 100644 --- a/src/network/socket/qsctpserver.h +++ b/src/network/socket/qsctpserver.h @@ -63,7 +63,7 @@ public: QSctpSocket *nextPendingDatagramConnection(); protected: - void incomingConnection(qintptr handle) Q_DECL_OVERRIDE; + void incomingConnection(qintptr handle) override; private: Q_DISABLE_COPY(QSctpServer) diff --git a/src/network/socket/qsctpserver_p.h b/src/network/socket/qsctpserver_p.h index 274939fc3d..8816cc150e 100644 --- a/src/network/socket/qsctpserver_p.h +++ b/src/network/socket/qsctpserver_p.h @@ -66,7 +66,7 @@ public: int maximumChannelCount; - void configureCreatedSocket() Q_DECL_OVERRIDE; + void configureCreatedSocket() override; }; #endif // QT_NO_SCTP diff --git a/src/network/socket/qsctpsocket.h b/src/network/socket/qsctpsocket.h index 9bed1890ff..5288da6129 100644 --- a/src/network/socket/qsctpsocket.h +++ b/src/network/socket/qsctpsocket.h @@ -56,8 +56,8 @@ public: explicit QSctpSocket(QObject *parent = nullptr); virtual ~QSctpSocket(); - void close() Q_DECL_OVERRIDE; - void disconnectFromHost() Q_DECL_OVERRIDE; + void close() override; + void disconnectFromHost() override; void setMaximumChannelCount(int count); int maximumChannelCount() const; @@ -67,8 +67,8 @@ public: bool writeDatagram(const QNetworkDatagram &datagram); protected: - qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 readLineData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; + qint64 readData(char *data, qint64 maxlen) override; + qint64 readLineData(char *data, qint64 maxlen) override; private: Q_DISABLE_COPY(QSctpSocket) diff --git a/src/network/socket/qsctpsocket_p.h b/src/network/socket/qsctpsocket_p.h index 3f765ebed9..8f9413cb47 100644 --- a/src/network/socket/qsctpsocket_p.h +++ b/src/network/socket/qsctpsocket_p.h @@ -70,8 +70,8 @@ public: QSctpSocketPrivate(); virtual ~QSctpSocketPrivate(); - bool canReadNotification() Q_DECL_OVERRIDE; - bool writeToSocket() Q_DECL_OVERRIDE; + bool canReadNotification() override; + bool writeToSocket() override; QByteArray incomingDatagram; int maximumChannelCount; @@ -80,7 +80,7 @@ public: QVector<IpHeaderList> readHeaders; QVector<IpHeaderList> writeHeaders; - void configureCreatedSocket() Q_DECL_OVERRIDE; + void configureCreatedSocket() override; }; #endif // QT_NO_SCTP diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index fa5f198bf2..a07ea65046 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -320,7 +320,7 @@ public: QSocks5BindData *retrieve(qintptr socketDescriptor); protected: - void timerEvent(QTimerEvent * event) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent * event) override; QMutex mutex; int sweepTimerId; diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h index b248554ae5..1942eff4ca 100644 --- a/src/network/socket/qsocks5socketengine_p.h +++ b/src/network/socket/qsocks5socketengine_p.h @@ -68,62 +68,62 @@ public: QSocks5SocketEngine(QObject *parent = 0); ~QSocks5SocketEngine(); - bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) Q_DECL_OVERRIDE; - bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) Q_DECL_OVERRIDE; + bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override; + bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) override; void setProxy(const QNetworkProxy &networkProxy); - qintptr socketDescriptor() const Q_DECL_OVERRIDE; + qintptr socketDescriptor() const override; - bool isValid() const Q_DECL_OVERRIDE; + bool isValid() const override; bool connectInternal(); - bool connectToHost(const QHostAddress &address, quint16 port) Q_DECL_OVERRIDE; - bool connectToHostByName(const QString &name, quint16 port) Q_DECL_OVERRIDE; - bool bind(const QHostAddress &address, quint16 port) Q_DECL_OVERRIDE; - bool listen() Q_DECL_OVERRIDE; - int accept() Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; + bool connectToHost(const QHostAddress &address, quint16 port) override; + bool connectToHostByName(const QString &name, quint16 port) override; + bool bind(const QHostAddress &address, quint16 port) override; + bool listen() override; + int accept() override; + void close() override; - qint64 bytesAvailable() const Q_DECL_OVERRIDE; + qint64 bytesAvailable() const override; - qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE; + qint64 read(char *data, qint64 maxlen) override; + qint64 write(const char *data, qint64 len) override; #ifndef QT_NO_UDPSOCKET #ifndef QT_NO_NETWORKINTERFACE bool joinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) Q_DECL_OVERRIDE; + const QNetworkInterface &interface) override; bool leaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) Q_DECL_OVERRIDE; - QNetworkInterface multicastInterface() const Q_DECL_OVERRIDE; - bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE; + const QNetworkInterface &interface) override; + QNetworkInterface multicastInterface() const override; + bool setMulticastInterface(const QNetworkInterface &iface) override; #endif // QT_NO_NETWORKINTERFACE - bool hasPendingDatagrams() const Q_DECL_OVERRIDE; - qint64 pendingDatagramSize() const Q_DECL_OVERRIDE; + bool hasPendingDatagrams() const override; + qint64 pendingDatagramSize() const override; #endif // QT_NO_UDPSOCKET qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0, - PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE; - qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE; - qint64 bytesToWrite() const Q_DECL_OVERRIDE; + PacketHeaderOptions = WantNone) override; + qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) override; + qint64 bytesToWrite() const override; - int option(SocketOption option) const Q_DECL_OVERRIDE; - bool setOption(SocketOption option, int value) Q_DECL_OVERRIDE; + int option(SocketOption option) const override; + bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; - bool waitForWrite(int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; + bool waitForRead(int msecs = 30000, bool *timedOut = 0) override; + bool waitForWrite(int msecs = 30000, bool *timedOut = 0) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = 0) Q_DECL_OVERRIDE; + int msecs = 30000, bool *timedOut = 0) override; - bool isReadNotificationEnabled() const Q_DECL_OVERRIDE; - void setReadNotificationEnabled(bool enable) Q_DECL_OVERRIDE; - bool isWriteNotificationEnabled() const Q_DECL_OVERRIDE; - void setWriteNotificationEnabled(bool enable) Q_DECL_OVERRIDE; - bool isExceptionNotificationEnabled() const Q_DECL_OVERRIDE; - void setExceptionNotificationEnabled(bool enable) Q_DECL_OVERRIDE; + bool isReadNotificationEnabled() const override; + void setReadNotificationEnabled(bool enable) override; + bool isWriteNotificationEnabled() const override; + void setWriteNotificationEnabled(bool enable) override; + bool isExceptionNotificationEnabled() const override; + void setExceptionNotificationEnabled(bool enable) override; private: Q_DECLARE_PRIVATE(QSocks5SocketEngine) @@ -166,11 +166,11 @@ class QSocks5PasswordAuthenticator : public QSocks5Authenticator { public: QSocks5PasswordAuthenticator(const QString &userName, const QString &password); - char methodId() Q_DECL_OVERRIDE; - bool beginAuthenticate(QTcpSocket *socket, bool *completed) Q_DECL_OVERRIDE; - bool continueAuthenticate(QTcpSocket *socket, bool *completed) Q_DECL_OVERRIDE; + char methodId() override; + bool beginAuthenticate(QTcpSocket *socket, bool *completed) override; + bool continueAuthenticate(QTcpSocket *socket, bool *completed) override; - QString errorString() Q_DECL_OVERRIDE; + QString errorString() override; private: QString userName; @@ -287,8 +287,8 @@ class Q_AUTOTEST_EXPORT QSocks5SocketEngineHandler : public QSocketEngineHandler { public: virtual QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType, - const QNetworkProxy &, QObject *parent) Q_DECL_OVERRIDE; - virtual QAbstractSocketEngine *createSocketEngine(qintptr socketDescriptor, QObject *parent) Q_DECL_OVERRIDE; + const QNetworkProxy &, QObject *parent) override; + virtual QAbstractSocketEngine *createSocketEngine(qintptr socketDescriptor, QObject *parent) override; }; QT_END_NAMESPACE diff --git a/src/network/socket/qtcpserver.h b/src/network/socket/qtcpserver.h index 192cbce54c..37df12919f 100644 --- a/src/network/socket/qtcpserver.h +++ b/src/network/socket/qtcpserver.h @@ -58,7 +58,7 @@ class Q_NETWORK_EXPORT QTcpServer : public QObject { Q_OBJECT public: - explicit QTcpServer(QObject *parent = Q_NULLPTR); + explicit QTcpServer(QObject *parent = nullptr); virtual ~QTcpServer(); bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); @@ -75,7 +75,7 @@ public: qintptr socketDescriptor() const; bool setSocketDescriptor(qintptr socketDescriptor); - bool waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR); + bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr); virtual bool hasPendingConnections() const; virtual QTcpSocket *nextPendingConnection(); @@ -95,7 +95,7 @@ protected: void addPendingConnection(QTcpSocket* socket); QTcpServer(QAbstractSocket::SocketType socketType, QTcpServerPrivate &dd, - QObject *parent = Q_NULLPTR); + QObject *parent = nullptr); Q_SIGNALS: void newConnection(); diff --git a/src/network/socket/qtcpserver_p.h b/src/network/socket/qtcpserver_p.h index b7fae4c105..6ee8c5f0b1 100644 --- a/src/network/socket/qtcpserver_p.h +++ b/src/network/socket/qtcpserver_p.h @@ -93,13 +93,13 @@ public: virtual void configureCreatedSocket(); // from QAbstractSocketEngineReceiver - void readNotification() Q_DECL_OVERRIDE; - void closeNotification() Q_DECL_OVERRIDE { readNotification(); } - void writeNotification() Q_DECL_OVERRIDE {} - void exceptionNotification() Q_DECL_OVERRIDE {} - void connectionNotification() Q_DECL_OVERRIDE {} + void readNotification() override; + void closeNotification() override { readNotification(); } + void writeNotification() override {} + void exceptionNotification() override {} + void connectionNotification() override {} #ifndef QT_NO_NETWORKPROXY - void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *) Q_DECL_OVERRIDE {} + void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *) override {} #endif }; diff --git a/src/network/socket/qtcpsocket.h b/src/network/socket/qtcpsocket.h index 3c3e3b69fd..b2c8bcc884 100644 --- a/src/network/socket/qtcpsocket.h +++ b/src/network/socket/qtcpsocket.h @@ -53,13 +53,13 @@ class Q_NETWORK_EXPORT QTcpSocket : public QAbstractSocket { Q_OBJECT public: - explicit QTcpSocket(QObject *parent = Q_NULLPTR); + explicit QTcpSocket(QObject *parent = nullptr); virtual ~QTcpSocket(); protected: - QTcpSocket(QTcpSocketPrivate &dd, QObject *parent = Q_NULLPTR); + QTcpSocket(QTcpSocketPrivate &dd, QObject *parent = nullptr); QTcpSocket(QAbstractSocket::SocketType socketType, QTcpSocketPrivate &dd, - QObject *parent = Q_NULLPTR); + QObject *parent = nullptr); private: Q_DISABLE_COPY(QTcpSocket) diff --git a/src/network/socket/qudpsocket.h b/src/network/socket/qudpsocket.h index 6ef10e2edb..ce4429d1cd 100644 --- a/src/network/socket/qudpsocket.h +++ b/src/network/socket/qudpsocket.h @@ -57,7 +57,7 @@ class Q_NETWORK_EXPORT QUdpSocket : public QAbstractSocket { Q_OBJECT public: - explicit QUdpSocket(QObject *parent = Q_NULLPTR); + explicit QUdpSocket(QObject *parent = nullptr); virtual ~QUdpSocket(); #ifndef QT_NO_NETWORKINTERFACE @@ -75,7 +75,7 @@ public: bool hasPendingDatagrams() const; qint64 pendingDatagramSize() const; QNetworkDatagram receiveDatagram(qint64 maxSize = -1); - qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host = Q_NULLPTR, quint16 *port = Q_NULLPTR); + qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host = nullptr, quint16 *port = nullptr); qint64 writeDatagram(const QNetworkDatagram &datagram); qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port); diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index b2ee1a8054..a8a37492b7 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -1,7 +1,6 @@ # Qt network socket HEADERS += socket/qabstractsocketengine_p.h \ - socket/qhttpsocketengine_p.h \ socket/qabstractsocket.h \ socket/qabstractsocket_p.h \ socket/qtcpsocket.h \ @@ -11,7 +10,6 @@ HEADERS += socket/qabstractsocketengine_p.h \ socket/qtcpserver_p.h SOURCES += socket/qabstractsocketengine.cpp \ - socket/qhttpsocketengine.cpp \ socket/qabstractsocket.cpp \ socket/qtcpsocket.cpp \ socket/qudpsocket.cpp \ @@ -26,6 +24,13 @@ qtConfig(socks5) { socket/qsocks5socketengine.cpp } +qtConfig(http) { + HEADERS += \ + socket/qhttpsocketengine_p.h + SOURCES += \ + socket/qhttpsocketengine.cpp +} + # SCTP support. qtConfig(sctp) { diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h index 8b051a5c88..6cd66fd20f 100644 --- a/src/network/ssl/qsslcertificate.h +++ b/src/network/ssl/qsslcertificate.h @@ -154,7 +154,7 @@ public: static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert, - QList<QSslCertificate> *caCertificates = Q_NULLPTR, + QList<QSslCertificate> *caCertificates = nullptr, const QByteArray &passPhrase=QByteArray()); Qt::HANDLE handle() const; diff --git a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp index 5ebad822f1..00e9be91d8 100644 --- a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp +++ b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp @@ -161,12 +161,12 @@ void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &pem) return; } - DH *dh = Q_NULLPTR; + DH *dh = nullptr; q_PEM_read_bio_DHparams(bio, &dh, 0, 0); if (dh) { if (isSafeDH(dh)) { - char *buf = Q_NULLPTR; + char *buf = nullptr; int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf)); if (len > 0) derData = QByteArray(buf, len); diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp index fd76d3353a..a85fed21ed 100644 --- a/src/network/ssl/qsslkey_qt.cpp +++ b/src/network/ssl/qsslkey_qt.cpp @@ -43,6 +43,7 @@ #include <QtCore/qdatastream.h> #include <QtCore/qcryptographichash.h> +#include <QtCore/qrandom.h> QT_USE_NAMESPACE @@ -286,10 +287,8 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) { // ### use a cryptographically secure random number generator - QByteArray iv; - iv.resize(8); - for (int i = 0; i < iv.size(); ++i) - iv[i] = (qrand() & 0xff); + quint64 random = QRandomGenerator::system()->generate64(); + QByteArray iv = QByteArray::fromRawData(reinterpret_cast<const char *>(&random), sizeof(random)); Cipher cipher = DesEde3Cbc; const QByteArray key = deriveKey(cipher, passPhrase, iv); diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index adff568f5b..145ae1a3c8 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2659,6 +2659,20 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize) /*! \internal */ +qint64 QSslSocketPrivate::skip(qint64 maxSize) +{ + if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) + return plainSocket->skip(maxSize); + + // In encrypted mode, the SSL backend writes decrypted data directly into the + // QIODevice's read buffer. As this buffer is always emptied by the caller, + // we need to wait for more incoming data. + return (state == QAbstractSocket::ConnectedState) ? Q_INT64_C(0) : Q_INT64_C(-1); +} + +/*! + \internal +*/ bool QSslSocketPrivate::flush() { #ifdef QSSLSOCKET_DEBUG diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h index 39e70bccda..c66ebdde54 100644 --- a/src/network/ssl/qsslsocket.h +++ b/src/network/ssl/qsslsocket.h @@ -79,22 +79,22 @@ public: AutoVerifyPeer }; - explicit QSslSocket(QObject *parent = Q_NULLPTR); + explicit QSslSocket(QObject *parent = nullptr); ~QSslSocket(); - void resume() Q_DECL_OVERRIDE; // to continue after proxy authentication required, SSL errors etc. + void resume() override; // to continue after proxy authentication required, SSL errors etc. // Autostarting the SSL client handshake. void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol); void connectToHostEncrypted(const QString &hostName, quint16 port, const QString &sslPeerName, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol); bool setSocketDescriptor(qintptr socketDescriptor, SocketState state = ConnectedState, - OpenMode openMode = ReadWrite) Q_DECL_OVERRIDE; + OpenMode openMode = ReadWrite) override; using QAbstractSocket::connectToHost; - void connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol) Q_DECL_OVERRIDE; - void disconnectFromHost() Q_DECL_OVERRIDE; + void connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol) override; + void disconnectFromHost() override; - virtual void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value) Q_DECL_OVERRIDE; - virtual QVariant socketOption(QAbstractSocket::SocketOption option) Q_DECL_OVERRIDE; + virtual void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value) override; + virtual QVariant socketOption(QAbstractSocket::SocketOption option) override; SslMode mode() const; bool isEncrypted() const; @@ -112,16 +112,16 @@ public: void setPeerVerifyName(const QString &hostName); // From QIODevice - qint64 bytesAvailable() const Q_DECL_OVERRIDE; - qint64 bytesToWrite() const Q_DECL_OVERRIDE; - bool canReadLine() const Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - bool atEnd() const Q_DECL_OVERRIDE; + qint64 bytesAvailable() const override; + qint64 bytesToWrite() const override; + bool canReadLine() const override; + void close() override; + bool atEnd() const override; bool flush(); // ### Qt6: remove me (implementation moved to private flush()) void abort(); // From QAbstractSocket: - void setReadBufferSize(qint64 size) Q_DECL_OVERRIDE; + void setReadBufferSize(qint64 size) override; // Similar to QIODevice's: qint64 encryptedBytesAvailable() const; @@ -179,11 +179,11 @@ public: QT_DEPRECATED_X("Use QSslConfiguration::systemCaCertificates()") static QList<QSslCertificate> systemCaCertificates(); #endif // QT_DEPRECATED_SINCE(5, 5) - bool waitForConnected(int msecs = 30000) Q_DECL_OVERRIDE; + bool waitForConnected(int msecs = 30000) override; bool waitForEncrypted(int msecs = 30000); - bool waitForReadyRead(int msecs = 30000) Q_DECL_OVERRIDE; - bool waitForBytesWritten(int msecs = 30000) Q_DECL_OVERRIDE; - bool waitForDisconnected(int msecs = 30000) Q_DECL_OVERRIDE; + bool waitForReadyRead(int msecs = 30000) override; + bool waitForBytesWritten(int msecs = 30000) override; + bool waitForDisconnected(int msecs = 30000) override; QList<QSslError> sslErrors() const; @@ -209,8 +209,8 @@ Q_SIGNALS: void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); protected: - qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE; + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; private: Q_DECLARE_PRIVATE(QSslSocket) diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp index 5312464964..046b432252 100644 --- a/src/network/ssl/qsslsocket_mac.cpp +++ b/src/network/ssl/qsslsocket_mac.cpp @@ -49,6 +49,7 @@ #include <QtCore/qmessageauthenticationcode.h> #include <QtCore/qoperatingsystemversion.h> #include <QtCore/qcryptographichash.h> +#include <QtCore/qsystemdetection.h> #include <QtCore/qdatastream.h> #include <QtCore/qsysinfo.h> #include <QtCore/qvector.h> @@ -161,14 +162,15 @@ EphemeralSecKeychain::~EphemeralSecKeychain() } #endif // Q_OS_MACOS -} + +} // unnamed namespace static SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode) { const bool isServer = mode == QSslSocket::SslServerMode; const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide; // We never use kSSLDatagramType, so it's kSSLStreamType unconditionally. - SSLContextRef context = SSLCreateContext(Q_NULLPTR, side, kSSLStreamType); + SSLContextRef context = SSLCreateContext(nullptr, side, kSSLStreamType); if (!context) qCWarning(lcSsl) << "SSLCreateContext failed"; return context; @@ -357,7 +359,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves() } QSslSocketBackendPrivate::QSslSocketBackendPrivate() - : context(Q_NULLPTR) + : context(nullptr) { } @@ -373,6 +375,43 @@ void QSslSocketBackendPrivate::continueHandshake() #endif Q_Q(QSslSocket); connectionEncrypted = true; + +#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0) + // Unlike OpenSSL, Secure Transport does not allow to negotiate protocols via + // a callback during handshake. We can only set our list of preferred protocols + // (and send it during handshake) and then receive what our peer has sent to us. + // And here we can finally try to find a match (if any). + if (__builtin_available(iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { + const auto &requestedProtocols = configuration.nextAllowedProtocols; + if (const int requestedCount = requestedProtocols.size()) { + configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone; + configuration.nextNegotiatedProtocol.clear(); + + QCFType<CFArrayRef> cfArray; + const OSStatus result = SSLCopyALPNProtocols(context, &cfArray); + if (result == errSecSuccess && cfArray && CFArrayGetCount(cfArray)) { + const int size = CFArrayGetCount(cfArray); + QVector<QString> peerProtocols(size); + for (int i = 0; i < size; ++i) + peerProtocols[i] = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(cfArray, i)); + + for (int i = 0; i < requestedCount; ++i) { + const auto requestedName = QString::fromLatin1(requestedProtocols[i]); + for (int j = 0; j < size; ++j) { + if (requestedName == peerProtocols[j]) { + configuration.nextNegotiatedProtocol = requestedName.toLatin1(); + configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated; + break; + } + } + if (configuration.nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNegotiated) + break; + } + } + } + } +#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE + emit q->encrypted(); if (autoStartHandshake && pendingClose) { pendingClose = false; @@ -839,6 +878,29 @@ bool QSslSocketBackendPrivate::initSslContext() return false; } +#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0) + if (__builtin_available(iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { + const auto protocolNames = configuration.nextAllowedProtocols; + QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks)); + if (cfNames) { + for (const QByteArray &name : protocolNames) { + QCFString cfName(QString::fromLatin1(name).toCFString()); + CFArrayAppendValue(cfNames, cfName); + } + + if (CFArrayGetCount(cfNames)) { + // Up to the application layer to check that negotiation + // failed, and handle this non-TLS error, we do not handle + // the result of this call as an error: + if (SSLSetALPNProtocols(context, cfNames) != errSecSuccess) + qCWarning(lcSsl) << "SSLSetALPNProtocols failed - too long protocol names?"; + } + } else { + qCWarning(lcSsl) << "failed to allocate ALPN names array"; + } + } +#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE + if (mode == QSslSocket::SslClientMode) { // enable Server Name Indication (SNI) QString tlsHostName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName); @@ -886,7 +948,7 @@ bool QSslSocketBackendPrivate::initSslContext() void QSslSocketBackendPrivate::destroySslContext() { - context.reset(Q_NULLPTR); + context.reset(nullptr); } static QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase); diff --git a/src/network/ssl/qsslsocket_mac_p.h b/src/network/ssl/qsslsocket_mac_p.h index 9e1d18981e..34e30ebb16 100644 --- a/src/network/ssl/qsslsocket_mac_p.h +++ b/src/network/ssl/qsslsocket_mac_p.h @@ -86,14 +86,14 @@ public: virtual ~QSslSocketBackendPrivate(); // Final-overriders (QSslSocketPrivate): - void continueHandshake() Q_DECL_OVERRIDE; - void disconnected() Q_DECL_OVERRIDE; - void disconnectFromHost() Q_DECL_OVERRIDE; - QSslCipher sessionCipher() const Q_DECL_OVERRIDE; - QSsl::SslProtocol sessionProtocol() const Q_DECL_OVERRIDE; - void startClientEncryption() Q_DECL_OVERRIDE; - void startServerEncryption() Q_DECL_OVERRIDE; - void transmit() Q_DECL_OVERRIDE; + void continueHandshake() override; + void disconnected() override; + void disconnectFromHost() override; + QSslCipher sessionCipher() const override; + QSsl::SslProtocol sessionProtocol() const override; + void startClientEncryption() override; + void startServerEncryption() override; + void transmit() override; static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName); diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index 7f9e884045..2a800cdc34 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -132,22 +132,22 @@ public: #endif // Platform specific functions - void startClientEncryption() Q_DECL_OVERRIDE; - void startServerEncryption() Q_DECL_OVERRIDE; - void transmit() Q_DECL_OVERRIDE; + void startClientEncryption() override; + void startServerEncryption() override; + void transmit() override; bool startHandshake(); - void disconnectFromHost() Q_DECL_OVERRIDE; - void disconnected() Q_DECL_OVERRIDE; - QSslCipher sessionCipher() const Q_DECL_OVERRIDE; - QSsl::SslProtocol sessionProtocol() const Q_DECL_OVERRIDE; - void continueHandshake() Q_DECL_OVERRIDE; + void disconnectFromHost() override; + void disconnected() override; + QSslCipher sessionCipher() const override; + QSsl::SslProtocol sessionProtocol() const override; + void continueHandshake() override; 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; + void _q_caRootLoaded(QSslCertificate,QSslCertificate) override; #endif Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions); diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index 3a236a1300..1b73135935 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -1017,7 +1017,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(EC_GROUP_get_degree) #endif RESOLVEFUNC(BN_num_bits) -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if QT_CONFIG(opensslv11) RESOLVEFUNC(BN_is_word) #endif RESOLVEFUNC(BN_mod_word) diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 796bf2d4f5..4cad0231cd 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -232,9 +232,10 @@ BIO *q_BIO_new_mem_buf(void *a, int b); int q_BIO_read(BIO *a, void *b, int c); Q_AUTOTEST_EXPORT int q_BIO_write(BIO *a, const void *b, int c); int q_BN_num_bits(const BIGNUM *a); -#if OPENSSL_VERSION_NUMBER >= 0x10100000L + +#if QT_CONFIG(opensslv11) int q_BN_is_word(BIGNUM *a, BN_ULONG w); -#else +#else // opensslv11 // BN_is_word is implemented purely as a // macro in OpenSSL < 1.1. It doesn't // call any functions. @@ -245,7 +246,8 @@ int q_BN_is_word(BIGNUM *a, BN_ULONG w); // // Users are required to include <openssl/bn.h>. #define q_BN_is_word BN_is_word -#endif // OPENSSL_VERSION_NUMBER >= 0x10100000L +#endif // !opensslv11 + BN_ULONG q_BN_mod_word(const BIGNUM *a, BN_ULONG w); #ifndef OPENSSL_NO_EC const EC_GROUP* q_EC_KEY_get0_group(const EC_KEY* k); diff --git a/src/network/ssl/qsslsocket_opensslpre11.cpp b/src/network/ssl/qsslsocket_opensslpre11.cpp index e51888c5f2..8ad4d5b521 100644 --- a/src/network/ssl/qsslsocket_opensslpre11.cpp +++ b/src/network/ssl/qsslsocket_opensslpre11.cpp @@ -290,8 +290,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) - s_loadRootCertsOnDemand = true; + s_loadRootCertsOnDemand = true; #endif } diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 00fda43b7e..ced861805b 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -170,7 +170,7 @@ public: static void checkSettingSslContext(QSslSocket*, QSharedPointer<QSslContext>); static QSharedPointer<QSslContext> sslContext(QSslSocket *socket); bool isPaused() const; - bool bind(const QHostAddress &address, quint16, QAbstractSocket::BindMode) Q_DECL_OVERRIDE; + bool bind(const QHostAddress &address, quint16, QAbstractSocket::BindMode) override; void _q_connectedSlot(); void _q_hostFoundSlot(); void _q_disconnectedSlot(); @@ -190,9 +190,10 @@ public: static QList<QByteArray> unixRootCertDirectories(); // used also by QSslContext - virtual qint64 peek(char *data, qint64 maxSize) Q_DECL_OVERRIDE; - virtual QByteArray peek(qint64 maxSize) Q_DECL_OVERRIDE; - bool flush() Q_DECL_OVERRIDE; + virtual qint64 peek(char *data, qint64 maxSize) override; + virtual QByteArray peek(qint64 maxSize) override; + qint64 skip(qint64 maxSize) override; + bool flush() 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 762b393738..f64ae2e020 100644 --- a/src/network/ssl/qsslsocket_winrt.cpp +++ b/src/network/ssl/qsslsocket_winrt.cpp @@ -522,7 +522,7 @@ HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus QList<QSslCertificate> peerCertificateChain; if (certificate) { ComPtr<IAsyncOperation<CertificateChain *>> op; - hr = certificate->BuildChainAsync(Q_NULLPTR, &op); + hr = certificate->BuildChainAsync(nullptr, &op); Q_ASSERT_SUCCEEDED(hr); ComPtr<ICertificateChain> certificateChain; hr = QWinRTFunctions::await(op, certificateChain.GetAddressOf()); diff --git a/src/network/ssl/qsslsocket_winrt_p.h b/src/network/ssl/qsslsocket_winrt_p.h index 1043aeee11..030db6d4fa 100644 --- a/src/network/ssl/qsslsocket_winrt_p.h +++ b/src/network/ssl/qsslsocket_winrt_p.h @@ -80,14 +80,14 @@ public: ~QSslSocketBackendPrivate(); // Platform specific functions - void startClientEncryption() Q_DECL_OVERRIDE; - void startServerEncryption() Q_DECL_OVERRIDE; - void transmit() Q_DECL_OVERRIDE; - void disconnectFromHost() Q_DECL_OVERRIDE; - void disconnected() Q_DECL_OVERRIDE; - QSslCipher sessionCipher() const Q_DECL_OVERRIDE; - QSsl::SslProtocol sessionProtocol() const Q_DECL_OVERRIDE; - void continueHandshake() Q_DECL_OVERRIDE; + void startClientEncryption() override; + void startServerEncryption() override; + void transmit() override; + void disconnectFromHost() override; + void disconnected() override; + QSslCipher sessionCipher() const override; + QSsl::SslProtocol sessionProtocol() const override; + void continueHandshake() override; static QList<QSslCipher> defaultCiphers(); static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName); |