diff options
Diffstat (limited to 'src/network')
30 files changed, 412 insertions, 515 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri index e829d52cbe..42c7c80f3b 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -78,6 +78,8 @@ ios { OBJECTIVE_SOURCES += \ access/qnetworkreplynsurlconnectionimpl.mm + + LIBS_PRIVATE += -framework Foundation } include($$PWD/../../3rdparty/zlib_dependency.pri) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index c4cb8e65c0..bb1580044f 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -263,7 +263,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair) request.setContentLength(uploadByteDevice->size()); } else if (request.contentLength() != -1 && uploadByteDevice->size() == -1) { // everything OK, the user supplied us the contentLength - } else if (request.contentLength() == -1 && uploadByteDevice->size() == -1) { + } else if (Q_UNLIKELY(request.contentLength() == -1 && uploadByteDevice->size() == -1)) { qFatal("QHttpNetworkConnectionPrivate: Neither content-length nor upload device size were given"); } } diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index ad8a5321b4..05457decc4 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -993,7 +993,7 @@ void QNetworkReplyHttpImplPrivate::initCacheSaveDevice() q->connect(cacheSaveDevice, SIGNAL(aboutToClose()), SLOT(_q_cacheSaveDeviceAboutToClose())); if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) { - if (cacheSaveDevice && !cacheSaveDevice->isOpen()) + if (Q_UNLIKELY(cacheSaveDevice && !cacheSaveDevice->isOpen())) qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- " "class %s probably needs to be fixed", managerPrivate->networkCache->metaObject()->className()); @@ -1733,7 +1733,7 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation() // ensure this function is only being called once if (state == Working) { - qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); + qDebug() << "QNetworkReplyHttpImplPrivate::_q_startOperation was called more than once" << url; return; } state = Working; @@ -2216,7 +2216,7 @@ void QNetworkReplyHttpImplPrivate::setCachingEnabled(bool enable) return; // nothing to do either! if (enable) { - if (bytesDownloaded) { + if (Q_UNLIKELY(bytesDownloaded)) { qDebug() << "setCachingEnabled: " << bytesDownloaded << " bytesDownloaded"; // refuse to enable in this case qCritical("QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written"); diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 7961a1dbae..681c88e87b 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -67,7 +67,7 @@ void QNetworkReplyImplPrivate::_q_startOperation() { // ensure this function is only being called once if (state == Working || state == Finished) { - qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); + qDebug() << "QNetworkReplyImpl::_q_startOperation was called more than once" << url; return; } state = Working; @@ -517,7 +517,7 @@ void QNetworkReplyImplPrivate::setCachingEnabled(bool enable) return; // nothing to do either! if (enable) { - if (bytesDownloaded) { + if (Q_UNLIKELY(bytesDownloaded)) { // refuse to enable in this case qCritical("QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written"); return; @@ -606,7 +606,7 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice() cacheSaveDevice = networkCache()->prepare(metaData); if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) { - if (cacheSaveDevice && !cacheSaveDevice->isOpen()) + if (Q_UNLIKELY(cacheSaveDevice && !cacheSaveDevice->isOpen())) qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- " "class %s probably needs to be fixed", networkCache()->metaObject()->className()); @@ -680,7 +680,7 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data) return; // read until EOF from data - if (copyDevice) { + if (Q_UNLIKELY(copyDevice)) { qCritical("QNetworkReplyImpl: copy from QIODevice already in progress -- " "backend probly needs to be fixed"); return; diff --git a/src/network/bearer/qnetworkconfiguration.cpp b/src/network/bearer/qnetworkconfiguration.cpp index 378245ce3e..b68abce380 100644 --- a/src/network/bearer/qnetworkconfiguration.cpp +++ b/src/network/bearer/qnetworkconfiguration.cpp @@ -35,11 +35,6 @@ #include "qnetworkconfiguration_p.h" #include <QDebug> -#ifdef Q_OS_BLACKBERRY -#include "private/qcore_unix_p.h" // qt_safe_open -#include <sys/pps.h> -#endif // Q_OS_BLACKBERRY - QT_BEGIN_NAMESPACE /*! @@ -202,77 +197,6 @@ QT_BEGIN_NAMESPACE \value BearerLTE The configuration is for a LTE (4G) interface. */ -#ifdef Q_OS_BLACKBERRY -static const char cellularStatusFile[] = "/pps/services/radioctrl/modem0/status_public"; - -static QNetworkConfiguration::BearerType cellularStatus() -{ - QNetworkConfiguration::BearerType ret = QNetworkConfiguration::BearerUnknown; - - int cellularStatusFD; - if ((cellularStatusFD = qt_safe_open(cellularStatusFile, O_RDONLY)) == -1) { - qWarning() << "failed to open" << cellularStatusFile; - return ret; - } - char buf[2048]; - if (qt_safe_read(cellularStatusFD, &buf, sizeof(buf)) == -1) { - qWarning() << "read from PPS file failed:" << strerror(errno); - qt_safe_close(cellularStatusFD); - return ret; - } - pps_decoder_t ppsDecoder; - if (pps_decoder_initialize(&ppsDecoder, buf) != PPS_DECODER_OK) { - qWarning("failed to initialize PPS decoder"); - qt_safe_close(cellularStatusFD); - return ret; - } - pps_decoder_error_t err; - if ((err = pps_decoder_push(&ppsDecoder, 0)) != PPS_DECODER_OK) { - qWarning() << "pps_decoder_push failed" << err; - pps_decoder_cleanup(&ppsDecoder); - qt_safe_close(cellularStatusFD); - return ret; - } - if (!pps_decoder_is_integer(&ppsDecoder, "network_technology")) { - qWarning("field has not the expected data type"); - pps_decoder_cleanup(&ppsDecoder); - qt_safe_close(cellularStatusFD); - return ret; - } - int type; - if (!pps_decoder_get_int(&ppsDecoder, "network_technology", &type) - == PPS_DECODER_OK) { - qWarning("could not read bearer type from PPS"); - pps_decoder_cleanup(&ppsDecoder); - qt_safe_close(cellularStatusFD); - return ret; - } - switch (type) { - case 0: // 0 == NONE - break; // unhandled - case 1: // fallthrough, 1 == GSM - case 4: // 4 == CDMA_1X - ret = QNetworkConfiguration::Bearer2G; - break; - case 2: // 2 == UMTS - ret = QNetworkConfiguration::BearerWCDMA; - break; - case 8: // 8 == EVDO - ret = QNetworkConfiguration::BearerEVDO; - break; - case 16: // 16 == LTE - ret = QNetworkConfiguration::BearerLTE; - break; - default: - qWarning() << "unhandled bearer type" << type; - break; - } - pps_decoder_cleanup(&ppsDecoder); - qt_safe_close(cellularStatusFD); - return ret; -} -#endif // Q_OS_BLACKBERRY - /*! Constructs an invalid configuration object. @@ -494,19 +418,6 @@ QNetworkConfiguration::BearerType QNetworkConfiguration::bearerType() const return BearerUnknown; QMutexLocker locker(&d->mutex); - -#ifdef Q_OS_BLACKBERRY - // for cellular configurations, we need to determine the exact - // type right now, because it might have changed after the last scan - if (d->bearerType == QNetworkConfiguration::Bearer2G) { - QNetworkConfiguration::BearerType type = cellularStatus(); - // if reading the status failed for some reason, just - // fall back to 2G - return (type == QNetworkConfiguration::BearerUnknown) - ? QNetworkConfiguration::Bearer2G : type; - } -#endif // Q_OS_BLACKBERRY - return d->bearerType; } @@ -639,20 +550,6 @@ QString QNetworkConfiguration::bearerTypeName() const case BearerWLAN: return QStringLiteral("WLAN"); case Bearer2G: -#ifdef Q_OS_BLACKBERRY - { - // for cellular configurations, we need to determine the exact - // type right now, because it might have changed after the last scan - QNetworkConfiguration::BearerType type = cellularStatus(); - if (type == QNetworkConfiguration::BearerWCDMA) { - return QStringLiteral("WCDMA"); - } else if (type == QNetworkConfiguration::BearerEVDO) { - return QStringLiteral("EVDO"); - }else if (type == QNetworkConfiguration::BearerLTE) { - return QStringLiteral("LTE"); - } - } -#endif // Q_OS_BLACKBERRY return QStringLiteral("2G"); case Bearer3G: return QStringLiteral("3G"); diff --git a/src/network/bearer/qnetworkconfiguration_p.h b/src/network/bearer/qnetworkconfiguration_p.h index 75df36fbd9..c8d926e32f 100644 --- a/src/network/bearer/qnetworkconfiguration_p.h +++ b/src/network/bearer/qnetworkconfiguration_p.h @@ -51,10 +51,6 @@ #include <QtCore/qmutex.h> #include <QtCore/qmap.h> -#ifdef Q_OS_BLACKBERRY -#include <bps/netstatus.h> -#endif - QT_BEGIN_NAMESPACE typedef QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> QNetworkConfigurationPrivatePointer; @@ -66,9 +62,6 @@ public: type(QNetworkConfiguration::Invalid), purpose(QNetworkConfiguration::UnknownPurpose), bearerType(QNetworkConfiguration::BearerUnknown), -#ifdef Q_OS_BLACKBERRY - oldIpStatus(NETSTATUS_IP_STATUS_ERROR_UNKNOWN), -#endif isValid(false), roamingSupported(false) {} virtual ~QNetworkConfigurationPrivate() @@ -89,10 +82,6 @@ public: QNetworkConfiguration::Purpose purpose; QNetworkConfiguration::BearerType bearerType; -#ifdef Q_OS_BLACKBERRY - netstatus_ip_status_t oldIpStatus; -#endif - bool isValid; bool roamingSupported; diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 435bfd6c27..8ca9366b0a 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -55,10 +55,6 @@ mac { mac:!ios:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:SOURCES += kernel/qnetworkproxy_win.cpp -else:blackberry { - SOURCES += kernel/qnetworkproxy_blackberry.cpp - LIBS_PRIVATE += -lbps -} else:contains(QT_CONFIG, libproxy) { SOURCES += kernel/qnetworkproxy_libproxy.cpp LIBS_PRIVATE += -lproxy diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp index a5e97c4a93..cb8129efc5 100644 --- a/src/network/kernel/qdnslookup_unix.cpp +++ b/src/network/kernel/qdnslookup_unix.cpp @@ -37,6 +37,7 @@ #include <qscopedpointer.h> #include <qurl.h> #include <private/qmutexpool_p.h> +#include <private/qnativesocketengine_p.h> #include <sys/types.h> #include <netinet/in.h> @@ -160,6 +161,7 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN state._u._ext.nscount6 = 1; ns->sin6_family = AF_INET6; ns->sin6_port = htons(53); + SetSALen::set(ns, sizeof(*ns)); Q_IPV6ADDR ipv6Address = nameserver.toIPv6Address(); for (int i=0; i<16; i++) { diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp index 4a527052d1..81906edc47 100644 --- a/src/network/kernel/qnetworkinterface.cpp +++ b/src/network/kernel/qnetworkinterface.cpp @@ -519,6 +519,31 @@ QList<QNetworkAddressEntry> QNetworkInterface::addressEntries() const } /*! + \since 5.7 + + Returns the index of the interface whose name is \a name or 0 if there is + no interface with that name. This function should produce the same result + as the following code, but will probably execute faster. + + \code + QNetworkInterface::interfaceFromName(name).index() + \endcode + + \sa interfaceFromName(), interfaceNameFromIndex(), QUdpDatagram::interfaceIndex() +*/ +int QNetworkInterface::interfaceIndexFromName(const QString &name) +{ + if (name.isEmpty()) + return 0; + + bool ok; + uint id = name.toUInt(&ok); + if (!ok) + id = QNetworkInterfaceManager::interfaceIndexFromName(name); + return int(id); +} + +/*! Returns a QNetworkInterface object for the interface named \a name. If no such interface exists, this function returns an invalid QNetworkInterface object. @@ -553,6 +578,27 @@ QNetworkInterface QNetworkInterface::interfaceFromIndex(int index) } /*! + \since 5.7 + + Returns the name of the interface whose index is \a index or an empty + string if there is no interface with that index. This function should + produce the same result as the following code, but will probably execute + faster. + + \code + QNetworkInterface::interfaceFromIndex(index).name() + \endcode + + \sa interfaceFromIndex(), interfaceIndexFromName(), QUdpDatagram::interfaceIndex() +*/ +QString QNetworkInterface::interfaceNameFromIndex(int index) +{ + if (!index) + return QString(); + return QNetworkInterfaceManager::interfaceNameFromIndex(index); +} + +/*! Returns a listing of all the network interfaces found on the host machine. In case of failure it returns a list with zero elements. */ diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h index b3daa3d4a0..bd57aea1cb 100644 --- a/src/network/kernel/qnetworkinterface.h +++ b/src/network/kernel/qnetworkinterface.h @@ -113,8 +113,10 @@ public: QString hardwareAddress() const; QList<QNetworkAddressEntry> addressEntries() const; + static int interfaceIndexFromName(const QString &name); static QNetworkInterface interfaceFromName(const QString &name); static QNetworkInterface interfaceFromIndex(int index); + static QString interfaceNameFromIndex(int index); static QList<QNetworkInterface> allInterfaces(); static QList<QHostAddress> allAddresses(); diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h index 140a28c536..146ba7820c 100644 --- a/src/network/kernel/qnetworkinterface_p.h +++ b/src/network/kernel/qnetworkinterface_p.h @@ -100,6 +100,9 @@ public: QSharedDataPointer<QNetworkInterfacePrivate> interfaceFromIndex(int index); QList<QSharedDataPointer<QNetworkInterfacePrivate> > allInterfaces(); + static uint interfaceIndexFromName(const QString &name); + static QString interfaceNameFromIndex(uint index); + // convenience: QSharedDataPointer<QNetworkInterfacePrivate> empty; diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp index cc53087024..541c78d838 100644 --- a/src/network/kernel/qnetworkinterface_unix.cpp +++ b/src/network/kernel/qnetworkinterface_unix.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 Intel Corporation. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtNetwork module of the Qt Toolkit. @@ -93,14 +94,8 @@ static QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex = 0, const QSt // this is the most likely scenario: // a scope ID in a socket is that of the interface this address came from address.setScopeId(ifname); - } else if (scope) { -#ifndef QT_NO_IPV6IFNAME - char scopeid[IFNAMSIZ]; - if (::if_indextoname(scope, scopeid)) { - address.setScopeId(QLatin1String(scopeid)); - } else -#endif - address.setScopeId(QString::number(uint(scope))); + } else if (scope) { + address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(scope)); } } return address; @@ -124,6 +119,53 @@ static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags) return flags; } +uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name) +{ +#ifndef QT_NO_IPV6IFNAME + return ::if_nametoindex(name.toLatin1()); +#elif defined(SIOCGIFINDEX) + struct ifreq req; + int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0); + if (socket < 0) + return 0; + + QByteArray name8bit = name.toLatin1(); + memset(&req, 0, sizeof(ifreq)); + memcpy(req.ifr_name, name8bit, qMin<int>(name8bit.length() + 1, sizeof(req.ifr_name) - 1)); + + uint id = 0; + if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0) + id = req.ifr_ifindex; + qt_safe_close(socket); + return id; +#else + return 0; +#endif +} + +QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) +{ +#ifndef QT_NO_IPV6IFNAME + char buf[IF_NAMESIZE]; + if (::if_indextoname(index, buf)) + return QString::fromLatin1(buf); +#elif defined(SIOCGIFNAME) + struct ifreq req; + int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0); + if (socket >= 0) { + memset(&req, 0, sizeof(ifreq)); + 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); + } +#endif + return QString::number(uint(index)); +} + #ifdef QT_NO_GETIFADDRS // getifaddrs not available diff --git a/src/network/kernel/qnetworkinterface_win.cpp b/src/network/kernel/qnetworkinterface_win.cpp index 907638f73e..238f913846 100644 --- a/src/network/kernel/qnetworkinterface_win.cpp +++ b/src/network/kernel/qnetworkinterface_win.cpp @@ -57,8 +57,14 @@ QT_BEGIN_NAMESPACE +typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceIndexToLuid)(NET_IFINDEX, PNET_LUID); typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceLuidToName)(const NET_LUID *, PWSTR, SIZE_T); +typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceLuidToIndex)(const NET_LUID *, PNET_IFINDEX); +typedef NETIO_STATUS (WINAPI *PtrConvertInterfaceNameToLuid)(const WCHAR *, PNET_LUID); +static PtrConvertInterfaceIndexToLuid ptrConvertInterfaceIndexToLuid = 0; static PtrConvertInterfaceLuidToName ptrConvertInterfaceLuidToName = 0; +static PtrConvertInterfaceLuidToIndex ptrConvertInterfaceLuidToIndex = 0; +static PtrConvertInterfaceNameToLuid ptrConvertInterfaceNameToLuid = 0; static void resolveLibs() { @@ -71,10 +77,16 @@ static void resolveLibs() #if defined(Q_OS_WINCE) // since Windows Embedded Compact 7 + ptrConvertInterfaceIndexToLuid = (PtrConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceIndexToLuid"); ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceLuidToNameW"); + ptrConvertInterfaceLuidToIndex = (PtrConvertInterfaceLuidToIndex)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceLuidToIndex"); + ptrConvertInterfaceNameToLuid = (PtrConvertInterfaceNameToLuid)GetProcAddress(iphlpapiHnd, L"ConvertInterfaceNameToLuidW"); #else // since Windows Vista + ptrConvertInterfaceIndexToLuid = (PtrConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHnd, "ConvertInterfaceIndexToLuid"); ptrConvertInterfaceLuidToName = (PtrConvertInterfaceLuidToName)GetProcAddress(iphlpapiHnd, "ConvertInterfaceLuidToNameW"); + ptrConvertInterfaceLuidToIndex = (PtrConvertInterfaceLuidToIndex)GetProcAddress(iphlpapiHnd, "ConvertInterfaceLuidToIndex"); + ptrConvertInterfaceNameToLuid = (PtrConvertInterfaceNameToLuid)GetProcAddress(iphlpapiHnd, "ConvertInterfaceNameToLuidW"); #endif done = true; } @@ -92,13 +104,42 @@ static QHostAddress addressFromSockaddr(sockaddr *sa) address.setAddress(((sockaddr_in6 *)sa)->sin6_addr.s6_addr); int scope = ((sockaddr_in6 *)sa)->sin6_scope_id; if (scope) - address.setScopeId(QString::number(scope)); + address.setScopeId(QNetworkInterfaceManager::interfaceNameFromIndex(scope)); } else qWarning("Got unknown socket family %d", sa->sa_family); return address; } +uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name) +{ + resolveLibs(); + if (!ptrConvertInterfaceNameToLuid || !ptrConvertInterfaceLuidToIndex) + return 0; + + NET_IFINDEX id; + NET_LUID luid; + if (ptrConvertInterfaceNameToLuid(reinterpret_cast<const wchar_t *>(name.constData()), &luid) == NO_ERROR + && ptrConvertInterfaceLuidToIndex(&luid, &id) == NO_ERROR) + return uint(id); + return 0; +} + +QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) +{ + resolveLibs(); + if (ptrConvertInterfaceIndexToLuid && ptrConvertInterfaceLuidToName) { + NET_LUID luid; + if (ptrConvertInterfaceIndexToLuid(index, &luid) == NO_ERROR) { + WCHAR buf[IF_MAX_STRING_SIZE + 1]; + if (ptrConvertInterfaceLuidToName(&luid, buf, sizeof(buf)/sizeof(buf[0])) == NO_ERROR) + return QString::fromWCharArray(buf); + } + } + + return QString::number(index); +} + static QHash<QHostAddress, QHostAddress> ipv4Netmasks() { //Retrieve all the IPV4 addresses & netmasks diff --git a/src/network/kernel/qnetworkinterface_winrt.cpp b/src/network/kernel/qnetworkinterface_winrt.cpp index 1945b2427f..1e22ab15da 100644 --- a/src/network/kernel/qnetworkinterface_winrt.cpp +++ b/src/network/kernel/qnetworkinterface_winrt.cpp @@ -61,6 +61,19 @@ struct HostNameInfo { QString address; }; +uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name) +{ + // TBD - may not be possible + Q_UNUSED(name); + return 0; +} + +QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index) +{ + // TBD - may not be possible + return QString::number(index); +} + static QNetworkInterfacePrivate *interfaceFromProfile(IConnectionProfile *profile, QList<HostNameInfo> *hostList) { if (!profile) diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index 4c7c0c5442..4263938fdf 100644 --- a/src/network/kernel/qnetworkproxy.cpp +++ b/src/network/kernel/qnetworkproxy.cpp @@ -1530,12 +1530,6 @@ void QNetworkProxyFactory::setApplicationProxyFactory(QNetworkProxyFactory *fact SOCKS server for all queries. If SOCKS isn't enabled, it will use the HTTPS proxy for all TcpSocket and UrlRequest queries. - On BlackBerry, this function obtains proxy settings for the default - configuration using system configuration. The type will be set based on - protocol tag "http", "https", "ftp", respectively. By default, it - assumes http type. Proxy username and password are also set during - the query using system configuration. - On other systems, this function will pick up proxy settings from the "http_proxy" environment variable. This variable must be a URL using one of the following schemes: "http", "socks5" or "socks5h". @@ -1552,10 +1546,6 @@ void QNetworkProxyFactory::setApplicationProxyFactory(QNetworkProxyFactory *fact \li On Windows platforms, this function may take several seconds to execute depending on the configuration of the user's system. - - \li On BlackBerry, only UrlRequest and TcpSocket queries are supported. SOCKS is - not supported. The proxy credentials are only retrieved for the - default configuration. \endlist */ diff --git a/src/network/kernel/qnetworkproxy_blackberry.cpp b/src/network/kernel/qnetworkproxy_blackberry.cpp deleted file mode 100644 index ca30a65397..0000000000 --- a/src/network/kernel/qnetworkproxy_blackberry.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Research In Motion -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/** - * Some notes about the code: - * - * ** It is assumed that the system proxies are for url based requests - * ie. HTTP/HTTPS based. - */ - -#include <QtNetwork/qnetworkproxy.h> - -#ifndef QT_NO_NETWORKPROXY - - -#include <QtCore/qflags.h> -#include <QtCore/qurl.h> -#include <QtNetwork/qnetworkconfiguration.h> - -#include <bps/netstatus.h> -#include <errno.h> - - -QT_BEGIN_NAMESPACE - -QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query) -{ - if (query.url().scheme() == QLatin1String("file") - || query.url().scheme() == QLatin1String("qrc")) - return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy); - - if (query.queryType() != QNetworkProxyQuery::UrlRequest - && query.queryType() != QNetworkProxyQuery::TcpSocket) { - qWarning("Unsupported query type: %d", query.queryType()); - return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy); - } - - QUrl url; - if (query.queryType() == QNetworkProxyQuery::UrlRequest) { - url = query.url(); - } else if (query.queryType() == QNetworkProxyQuery::TcpSocket - && !query.peerHostName().isEmpty()) { - url.setHost(query.peerHostName()); - switch (query.peerPort()) { - case 443: - url.setScheme(QStringLiteral("https")); - break; - case 21: - url.setScheme(QStringLiteral("ftp")); - break; - default: - // for unknown ports, we just pretend we are dealing - // with a HTTP URL, otherwise we will not get a proxy - // from the netstatus API - url.setScheme(QStringLiteral("http")); - } - } - - if (!url.isValid()) { - qWarning("Invalid URL: %s", qPrintable(url.toString())); - return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy); - } - - netstatus_proxy_details_t details; - memset(&details, 0, sizeof(netstatus_proxy_details_t)); - -#if BPS_VERSION >= 3001001 - - QByteArray bUrl(url.toEncoded()); - QString sInterface(query.networkConfiguration().name()); - QByteArray bInterface; - if (!sInterface.isEmpty()) { - if (query.networkConfiguration().type() != QNetworkConfiguration::InternetAccessPoint) { - qWarning("Unsupported configuration type: %d", query.networkConfiguration().type()); - return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy); - } - bInterface = sInterface.toUtf8(); - } - - if (netstatus_get_proxy_details_for_url(bUrl.constData(), (bInterface.isEmpty() ? NULL : bInterface.constData()), &details) != BPS_SUCCESS) { - qWarning("netstatus_get_proxy_details_for_url failed! errno: %d", errno); - return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy); - } - -#else - - if (netstatus_get_proxy_details(&details) != BPS_SUCCESS) { - qWarning("netstatus_get_proxy_details failed! errno: %d", errno); - return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy); - } - -#endif - - if (details.http_proxy_host == NULL) { // No proxy - netstatus_free_proxy_details(&details); - return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy); - } - - QNetworkProxy proxy; - - QString protocol = query.protocolTag(); - if (protocol.startsWith(QLatin1String("http"), Qt::CaseInsensitive)) { // http, https - proxy.setType((QNetworkProxy::HttpProxy)); - } else if (protocol == QLatin1String("ftp")) { - proxy.setType(QNetworkProxy::FtpCachingProxy); - } else { // assume http proxy - qDebug("Proxy type: %s assumed to be http proxy", qPrintable(protocol)); - proxy.setType((QNetworkProxy::HttpProxy)); - } - - // Set host - // Note: ftp and https proxy type fields *are* obsolete. - // The user interface allows only one host/port which gets duplicated - // to all proxy type fields. - proxy.setHostName(QString::fromUtf8(details.http_proxy_host)); - - // Set port - proxy.setPort(details.http_proxy_port); - - // Set username - if (details.http_proxy_login_user) - proxy.setUser(QString::fromUtf8(details.http_proxy_login_user)); - - // Set password - if (details.http_proxy_login_password) - proxy.setPassword(QString::fromUtf8(details.http_proxy_login_password)); - - netstatus_free_proxy_details(&details); - - return QList<QNetworkProxy>() << proxy; -} - -QT_END_NAMESPACE - -#endif diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 1831d25718..ed86dbbbae 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -722,19 +722,9 @@ bool QAbstractSocketPrivate::canReadNotification() } } - // only emit readyRead() when not recursing, and only if there is data available - bool hasData = newBytes > 0 -#ifndef QT_NO_UDPSOCKET - || (!isBuffered && socketType != QAbstractSocket::TcpSocket && socketEngine && socketEngine->hasPendingDatagrams()) -#endif - || (!isBuffered && socketType == QAbstractSocket::TcpSocket && socketEngine) - ; - - if (!emittedReadyRead && hasData) { - QScopedValueRollback<bool> r(emittedReadyRead); - emittedReadyRead = true; - emit q->readyRead(); - } + // Only emit readyRead() if there is data available. + if (newBytes > 0 || !isBuffered) + emitReadyRead(); // If we were closed as a result of the readyRead() signal, // return. @@ -792,12 +782,12 @@ void QAbstractSocketPrivate::canCloseNotification() // then occur when we read from the socket again and fail // in canReadNotification or by the manually created // closeNotification below. - emit q->readyRead(); + emitReadyRead(); QMetaObject::invokeMethod(socketEngine, "closeNotification", Qt::QueuedConnection); } } else if (socketType == QAbstractSocket::TcpSocket && socketEngine) { - emit q->readyRead(); + emitReadyRead(); } } @@ -817,8 +807,7 @@ bool QAbstractSocketPrivate::canWriteNotification() #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canWriteNotification() flushing"); #endif - qint64 tmp = writeBuffer.size(); - flush(); + bool dataWasWritten = writeToSocket(); if (socketEngine) { #if defined (Q_OS_WIN) @@ -830,7 +819,7 @@ bool QAbstractSocketPrivate::canWriteNotification() #endif } - return (writeBuffer.size() < tmp); + return dataWasWritten; } /*! \internal @@ -852,21 +841,20 @@ void QAbstractSocketPrivate::connectionNotification() /*! \internal - Writes pending data in the write buffers to the socket. The - function writes as much as it can without blocking. + Writes one pending data block in the write buffer to the socket. It is usually invoked by canWriteNotification after one or more calls to write(). Emits bytesWritten(). */ -bool QAbstractSocketPrivate::flush() +bool QAbstractSocketPrivate::writeToSocket() { Q_Q(QAbstractSocket); if (!socketEngine || !socketEngine->isValid() || (writeBuffer.isEmpty() && socketEngine->bytesToWrite() == 0)) { #if defined (QABSTRACTSOCKET_DEBUG) - qDebug("QAbstractSocketPrivate::flush() nothing to do: valid ? %s, writeBuffer.isEmpty() ? %s", + qDebug("QAbstractSocketPrivate::writeToSocket() nothing to do: valid ? %s, writeBuffer.isEmpty() ? %s", (socketEngine && socketEngine->isValid()) ? "yes" : "no", writeBuffer.isEmpty() ? "yes" : "no"); #endif @@ -884,7 +872,8 @@ bool QAbstractSocketPrivate::flush() qint64 written = socketEngine->write(ptr, nextSize); if (written < 0) { #if defined (QABSTRACTSOCKET_DEBUG) - qDebug() << "QAbstractSocketPrivate::flush() write error, aborting." << socketEngine->errorString(); + qDebug() << "QAbstractSocketPrivate::writeToSocket() write error, aborting." + << socketEngine->errorString(); #endif setErrorAndEmit(socketEngine->error(), socketEngine->errorString()); // an unexpected error so close the socket. @@ -893,7 +882,7 @@ bool QAbstractSocketPrivate::flush() } #if defined (QABSTRACTSOCKET_DEBUG) - qDebug("QAbstractSocketPrivate::flush() %lld bytes written to the network", + qDebug("QAbstractSocketPrivate::writeToSocket() %lld bytes written to the network", written); #endif @@ -914,7 +903,23 @@ bool QAbstractSocketPrivate::flush() if (state == QAbstractSocket::ClosingState) q->disconnectFromHost(); - return true; + return written > 0; +} + +/*! \internal + + Writes pending data in the write buffers to the socket. The function + writes as much as it can without blocking. If any data was written, + this function returns true; otherwise false is returned. +*/ +bool QAbstractSocketPrivate::flush() +{ + bool dataWasWritten = false; + + while (!writeBuffer.isEmpty() && writeToSocket()) + dataWasWritten = true; + + return dataWasWritten; } #ifndef QT_NO_NETWORKPROXY @@ -1248,10 +1253,7 @@ void QAbstractSocketPrivate::_q_forceDisconnect() */ bool QAbstractSocketPrivate::readFromSocket() { -#ifdef QABSTRACTSOCKET_DEBUG Q_Q(QAbstractSocket); -#endif - // Find how many bytes we can read from the socket layer. qint64 bytesToRead = socketEngine->bytesAvailable(); if (bytesToRead == 0) { @@ -1280,7 +1282,7 @@ bool QAbstractSocketPrivate::readFromSocket() buffer.chop(bytesToRead); return true; } - buffer.chop(bytesToRead - (readBytes < 0 ? qint64(0) : readBytes)); + buffer.chop(bytesToRead - ((readBytes < 0 || !q->isReadable()) ? qint64(0) : readBytes)); #if defined(QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::readFromSocket() got %lld bytes, buffer size = %lld", readBytes, buffer.size()); @@ -1301,6 +1303,21 @@ bool QAbstractSocketPrivate::readFromSocket() /*! \internal + Prevents from the recursive readyRead() emission. +*/ +void QAbstractSocketPrivate::emitReadyRead() +{ + Q_Q(QAbstractSocket); + // Only emit readyRead() when not recursing. + if (!emittedReadyRead) { + QScopedValueRollback<bool> r(emittedReadyRead); + emittedReadyRead = true; + emit q->readyRead(); + } +} + +/*! \internal + Sets up the internal state after the connection has succeeded. */ void QAbstractSocketPrivate::fetchConnectionParameters() @@ -2378,7 +2395,7 @@ bool QAbstractSocket::isSequential() const */ bool QAbstractSocket::atEnd() const { - return QIODevice::atEnd() && (!isOpen() || d_func()->buffer.isEmpty()); + return QIODevice::atEnd(); } /*! diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index 23f0d26cbd..f8edc74a24 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -176,7 +176,7 @@ public: // from QIODevice void close() Q_DECL_OVERRIDE; bool isSequential() const Q_DECL_OVERRIDE; - bool atEnd() const Q_DECL_OVERRIDE; + bool atEnd() const Q_DECL_OVERRIDE; // ### Qt6: remove me bool flush(); // for synchronous access diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index a905625b19..ba129b48df 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -135,6 +135,8 @@ public: void fetchConnectionParameters(); void setupSocketNotifiers(); bool readFromSocket(); + bool writeToSocket(); + void emitReadyRead(); void setError(QAbstractSocket::SocketError errorCode, const QString &errorString); void setErrorAndEmit(QAbstractSocket::SocketError errorCode, const QString &errorString); diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 92ca76b560..3f20e5c046 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -768,7 +768,6 @@ void QHttpSocketEngine::emitPendingConnectionNotification() void QHttpSocketEngine::emitReadNotification() { Q_D(QHttpSocketEngine); - d->readNotificationActivated = true; // if there is a connection notification pending we have to emit the readNotification // incase there is connection error. This is only needed for Windows, but it does not // hurt in other cases. @@ -781,7 +780,6 @@ void QHttpSocketEngine::emitReadNotification() void QHttpSocketEngine::emitWriteNotification() { Q_D(QHttpSocketEngine); - d->writeNotificationActivated = true; if (d->writeNotificationEnabled && !d->writeNotificationPending) { d->writeNotificationPending = true; QMetaObject::invokeMethod(this, "emitPendingWriteNotification", Qt::QueuedConnection); @@ -801,8 +799,6 @@ QHttpSocketEnginePrivate::QHttpSocketEnginePrivate() : readNotificationEnabled(false) , writeNotificationEnabled(false) , exceptNotificationEnabled(false) - , readNotificationActivated(false) - , writeNotificationActivated(false) , readNotificationPending(false) , writeNotificationPending(false) , connectionNotificationPending(false) diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h index 41c63fe11e..b34e5b0dc3 100644 --- a/src/network/socket/qhttpsocketengine_p.h +++ b/src/network/socket/qhttpsocketengine_p.h @@ -172,8 +172,6 @@ public: bool readNotificationEnabled; bool writeNotificationEnabled; bool exceptNotificationEnabled; - bool readNotificationActivated; - bool writeNotificationActivated; bool readNotificationPending; bool writeNotificationPending; bool connectionNotificationPending; diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 9a76e23013..2dc4bbaced 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -45,6 +45,7 @@ // We mean it. // #include "QtNetwork/qhostaddress.h" +#include "QtNetwork/qnetworkinterface.h" #include "private/qabstractsocketengine_p.h" #ifndef Q_OS_WIN # include "qplatformdefs.h" @@ -98,6 +99,16 @@ union qt_sockaddr { sockaddr_in6 a6; }; +namespace { +namespace SetSALen { + template <typename T> void set(T *sa, typename QtPrivate::QEnableIf<(&T::sa_len, true), QT_SOCKLEN_T>::Type len) + { sa->sa_len = len; } + template <typename T> void set(T *sin6, typename QtPrivate::QEnableIf<(&T::sin6_len, true), QT_SOCKLEN_T>::Type len) + { sin6->sin6_len = len; } + template <typename T> void set(T *, ...) {} +} +} + class QNativeSocketEnginePrivate; #ifndef QT_NO_NETWORKINTERFACE class QNetworkInterface; @@ -266,7 +277,8 @@ public: bool checkProxy(const QHostAddress &address); bool fetchConnectionParameters(); - static uint scopeIdFromString(const QString &scopeid); + static uint scopeIdFromString(const QString &scopeid) + { return QNetworkInterface::interfaceIndexFromName(scopeid); } /*! \internal Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize. @@ -285,12 +297,14 @@ public: Q_IPV6ADDR tmp = address.toIPv6Address(); memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp)); *sockAddrSize = sizeof(sockaddr_in6); + SetSALen::set(&aa->a, sizeof(sockaddr_in6)); } else { memset(&aa->a, 0, sizeof(sockaddr_in)); aa->a4.sin_family = AF_INET; aa->a4.sin_port = htons(port); aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address()); *sockAddrSize = sizeof(sockaddr_in); + SetSALen::set(&aa->a, sizeof(sockaddr_in)); } } diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 8626a6be0f..2ed39fcc0a 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -107,15 +107,8 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po QHostAddress tmpAddress; tmpAddress.setAddress(tmp); *addr = tmpAddress; - if (s->a6.sin6_scope_id) { -#ifndef QT_NO_IPV6IFNAME - char scopeid[IFNAMSIZ]; - if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) { - addr->setScopeId(QLatin1String(scopeid)); - } else -#endif - addr->setScopeId(QString::number(s->a6.sin6_scope_id)); - } + if (s->a6.sin6_scope_id) + addr->setScopeId(QNetworkInterface::interfaceNameFromIndex(s->a6.sin6_scope_id)); } if (port) *port = ntohs(s->a6.sin6_port); @@ -131,21 +124,6 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po } } -// inline on purpose -inline uint QNativeSocketEnginePrivate::scopeIdFromString(const QString &scopeid) -{ - if (scopeid.isEmpty()) - return 0; - - bool ok; - uint id = scopeid.toUInt(&ok); -#ifndef QT_NO_IPV6IFNAME - if (!ok) - id = ::if_nametoindex(scopeid.toLatin1()); -#endif - return id; -} - static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n) { @@ -1207,53 +1185,6 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) return qint64(r); } -#ifdef Q_OS_BLACKBERRY -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const -{ - fd_set fds; - FD_ZERO(&fds); - FD_SET(socketDescriptor, &fds); - - int retval; - QList<QSocketNotifier *> notifiers; - if (selectForRead) { - notifiers << readNotifier; - retval = bb_select(notifiers, socketDescriptor + 1, &fds, 0, timeout); - } else { - notifiers << writeNotifier; - retval = bb_select(notifiers, socketDescriptor + 1, 0, &fds, timeout); - } - - return retval; -} - -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const -{ - fd_set fdread; - FD_ZERO(&fdread); - if (checkRead) - FD_SET(socketDescriptor, &fdread); - - fd_set fdwrite; - FD_ZERO(&fdwrite); - if (checkWrite) - FD_SET(socketDescriptor, &fdwrite); - - QList<QSocketNotifier *> notifiers; - notifiers << readNotifier << writeNotifier; - int ret = bb_select(notifiers, socketDescriptor + 1, &fdread, &fdwrite, timeout); - - if (ret <= 0) - return ret; - *selectForRead = FD_ISSET(socketDescriptor, &fdread); - *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite); - - return ret; -} - -#else // not Q_OS_BLACKBERRY: - int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const { fd_set fds; @@ -1300,6 +1231,5 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c return ret; } -#endif // Q_OS_BLACKBERRY QT_END_NAMESPACE diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 9aed0caa25..1379ed93ba 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -322,12 +322,6 @@ static inline int qt_socket_getMaxMsgSize(qintptr socketDescriptor) # define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) #endif -// inline on purpose -inline uint QNativeSocketEnginePrivate::scopeIdFromString(const QString &scopeid) -{ - return scopeid.toUInt(); -} - bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol) { @@ -657,6 +651,13 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin int tries = 0; do { if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) { + if (value != NOERROR) { + // MSDN says getsockopt with SO_ERROR clears the error, but it's not actually cleared + // and this can affect all subsequent WSAConnect attempts, so clear it now. + const int val = NO_ERROR; + ::setsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, reinterpret_cast<const char*>(&val), sizeof val); + } + if (value == WSAECONNREFUSED) { setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); socketState = QAbstractSocket::UnconnectedState; diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 805adc734f..1dfd87a0f8 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -1507,6 +1507,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates() returned by defaultCaCertificates(). You can replace that database with your own with setDefaultCaCertificates(). + \note: On OS X, only certificates that are either trusted for all + purposes or trusted for the purpose of SSL in the keychain will be + returned. + \sa caCertificates(), defaultCaCertificates(), setDefaultCaCertificates() */ QList<QSslCertificate> QSslSocket::systemCaCertificates() diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp index 4e090f96cb..326686fad0 100644 --- a/src/network/ssl/qsslsocket_mac.cpp +++ b/src/network/ssl/qsslsocket_mac.cpp @@ -491,29 +491,6 @@ void QSslSocketPrivate::resetDefaultEllipticCurves() Q_UNIMPLEMENTED(); } - -QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() -{ - QList<QSslCertificate> systemCerts; -#ifdef Q_OS_OSX - // SecTrustSettingsCopyCertificates is not defined on iOS. - QCFType<CFArrayRef> cfCerts; - OSStatus status = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts); - if (status == noErr) { - const CFIndex size = CFArrayGetCount(cfCerts); - for (CFIndex i = 0; i < size; ++i) { - SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); - QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert); - systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der); - } - } else { - // no detailed error handling here - qCWarning(lcSsl) << "SecTrustSettingsCopyCertificates failed:" << status; - } -#endif - return systemCerts; -} - QSslSocketBackendPrivate::QSslSocketBackendPrivate() : context(Q_NULLPTR) { @@ -867,6 +844,9 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA384"); break; + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + ciph.d->name = QLatin1String("ECDHE-RSA-AES256-GCM-SHA384"); + break; default: return ciph; } @@ -914,6 +894,10 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui ciph.d->encryptionMethod = QLatin1String("AES(128)"); ciph.d->bits = 128; ciph.d->supportedBits = 128; + } else if (ciph.d->name.contains("AES256-GCM")) { + ciph.d->encryptionMethod = QLatin1String("AESGCM(256)"); + ciph.d->bits = 256; + ciph.d->supportedBits = 256; } else if (ciph.d->name.contains("AES256-")) { ciph.d->encryptionMethod = QLatin1String("AES(256)"); ciph.d->bits = 256; diff --git a/src/network/ssl/qsslsocket_mac_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp new file mode 100644 index 0000000000..f44b20e938 --- /dev/null +++ b/src/network/ssl/qsslsocket_mac_shared.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 ownCloud Inc +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//#define QSSLSOCKET_DEBUG +//#define QT_DECRYPT_SSL_TRAFFIC + +#include "qssl_p.h" +#include "qsslsocket.h" + +#ifndef QT_NO_OPENSSL +# include "qsslsocket_openssl_p.h" +# include "qsslsocket_openssl_symbols_p.h" +#endif + +#include "qsslcertificate_p.h" + +#ifdef Q_OS_DARWIN +# include <private/qcore_mac_p.h> +#endif + +#include <QtCore/qdebug.h> + +#ifdef Q_OS_OSX +# include <Security/Security.h> +#endif + + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_OSX +namespace { + +bool hasTrustedSslServerPolicy(SecPolicyRef policy, CFDictionaryRef props) { + QCFType<CFDictionaryRef> policyProps = SecPolicyCopyProperties(policy); + // only accept certificates with policies for SSL server validation for now + if (CFEqual(CFDictionaryGetValue(policyProps, kSecPolicyOid), kSecPolicyAppleSSL)) { + CFBooleanRef policyClient; + if (CFDictionaryGetValueIfPresent(policyProps, kSecPolicyClient, reinterpret_cast<const void**>(&policyClient)) && + CFEqual(policyClient, kCFBooleanTrue)) { + return false; // no client certs + } + if (!CFDictionaryContainsKey(props, kSecTrustSettingsResult)) { + // as per the docs, no trust settings result implies full trust + return true; + } + CFNumberRef number = static_cast<CFNumberRef>(CFDictionaryGetValue(props, kSecTrustSettingsResult)); + SecTrustSettingsResult settingsResult; + CFNumberGetValue(number, kCFNumberSInt32Type, &settingsResult); + switch (settingsResult) { + case kSecTrustSettingsResultTrustRoot: + case kSecTrustSettingsResultTrustAsRoot: + return true; + default: + return false; + } + } + return false; +} + +bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain) +{ + QCFType<CFArrayRef> cfTrustSettings; + OSStatus status = SecTrustSettingsCopyTrustSettings(cfCert, SecTrustSettingsDomain(domain), &cfTrustSettings); + if (status == noErr) { + CFIndex size = CFArrayGetCount(cfTrustSettings); + // if empty, trust for everything (as per the Security Framework documentation) + if (size == 0) { + return true; + } else { + for (CFIndex i = 0; i < size; ++i) { + CFDictionaryRef props = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(cfTrustSettings, i)); + if (CFDictionaryContainsKey(props, kSecTrustSettingsPolicy)) { + if (hasTrustedSslServerPolicy((SecPolicyRef)CFDictionaryGetValue(props, kSecTrustSettingsPolicy), props)) + return true; + } + } + } + } else { + qCWarning(lcSsl, "Error receiving trust for a CA certificate"); + } + return false; +} + +} // anon namespace +#endif // Q_OS_OSX + +QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() +{ + ensureInitialized(); + + QList<QSslCertificate> systemCerts; + // SecTrustSettingsCopyCertificates is not defined on iOS. +#ifdef Q_OS_OSX + QCFType<CFArrayRef> cfCerts; + // iterate through all enum members, order: + // kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainSystem + for (int dom = kSecTrustSettingsDomainUser; dom <= int(kSecTrustSettingsDomainSystem); dom++) { + OSStatus status = SecTrustSettingsCopyCertificates(SecTrustSettingsDomain(dom), &cfCerts); + if (status == noErr) { + const CFIndex size = CFArrayGetCount(cfCerts); + for (CFIndex i = 0; i < size; ++i) { + SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); + QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert); + if (::isCaCertificateTrusted(cfCert, dom)) { + if (derData == NULL) { + qCWarning(lcSsl, "Error retrieving a CA certificate from the system store"); + } else { + systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der); + } + } + } + } + } +#endif + return systemCerts; +} + +QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index dd47dfc45f..bbd712317c 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -78,12 +78,7 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_MACX) -#define kSecTrustSettingsDomainSystem 2 // so we do not need to include the header file - PtrSecCertificateCopyData QSslSocketPrivate::ptrSecCertificateCopyData = 0; - PtrSecTrustSettingsCopyCertificates QSslSocketPrivate::ptrSecTrustSettingsCopyCertificates = 0; - PtrSecTrustCopyAnchorCertificates QSslSocketPrivate::ptrSecTrustCopyAnchorCertificates = 0; -#elif defined(Q_OS_WIN) +#if defined(Q_OS_WIN) PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = 0; PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0; PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0; @@ -506,23 +501,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #ifndef QT_NO_LIBRARY //load symbols needed to receive certificates from system store -#if defined(Q_OS_MACX) - QLibrary securityLib("/System/Library/Frameworks/Security.framework/Versions/Current/Security"); - if (securityLib.load()) { - ptrSecCertificateCopyData = (PtrSecCertificateCopyData) securityLib.resolve("SecCertificateCopyData"); - if (!ptrSecCertificateCopyData) - qCWarning(lcSsl, "could not resolve symbols in security library"); // should never happen - - ptrSecTrustSettingsCopyCertificates = (PtrSecTrustSettingsCopyCertificates) securityLib.resolve("SecTrustSettingsCopyCertificates"); - if (!ptrSecTrustSettingsCopyCertificates) { // method was introduced in Leopard, use legacy method if it's not there - ptrSecTrustCopyAnchorCertificates = (PtrSecTrustCopyAnchorCertificates) securityLib.resolve("SecTrustCopyAnchorCertificates"); - if (!ptrSecTrustCopyAnchorCertificates) - qCWarning(lcSsl, "could not resolve symbols in security library"); // should never happen - } - } else { - qCWarning(lcSsl, "could not load security library"); - } -#elif defined(Q_OS_WIN) +#if defined(Q_OS_WIN) HINSTANCE hLib = LoadLibraryW(L"Crypt32"); if (hLib) { #if defined(Q_OS_WINCE) @@ -680,6 +659,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves() setDefaultSupportedEllipticCurves(curves); } +#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() { ensureInitialized(); @@ -688,43 +668,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() timer.start(); #endif QList<QSslCertificate> systemCerts; -#if defined(Q_OS_MACX) - CFArrayRef cfCerts; - OSStatus status = 1; - - CFDataRef SecCertificateCopyData ( - SecCertificateRef certificate - ); - - if (ptrSecCertificateCopyData) { - if (ptrSecTrustSettingsCopyCertificates) - status = ptrSecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts); - else if (ptrSecTrustCopyAnchorCertificates) - status = ptrSecTrustCopyAnchorCertificates(&cfCerts); - if (!status) { - CFIndex size = CFArrayGetCount(cfCerts); - for (CFIndex i = 0; i < size; ++i) { - SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i); - CFDataRef data; - - data = ptrSecCertificateCopyData(cfCert); - - if (data == NULL) { - qCWarning(lcSsl, "error retrieving a CA certificate from the system store"); - } else { - QByteArray rawCert = QByteArray::fromRawData((const char *)CFDataGetBytePtr(data), CFDataGetLength(data)); - systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der)); - CFRelease(data); - } - } - CFRelease(cfCerts); - } - else { - // no detailed error handling here - qCWarning(lcSsl, "could not retrieve system CA certificates"); - } - } -#elif defined(Q_OS_WIN) +#if defined(Q_OS_WIN) if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) { HCERTSTORE hSystemStore; #if defined(Q_OS_WINCE) @@ -801,6 +745,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() return systemCerts; } +#endif // Q_OS_DARWIN void QSslSocketBackendPrivate::startClientEncryption() { diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index d6519718d9..17cc7b4259 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -151,11 +151,7 @@ public: static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName); Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname); -#if defined(Q_OS_MACX) - static PtrSecCertificateCopyData ptrSecCertificateCopyData; - static PtrSecTrustSettingsCopyCertificates ptrSecTrustSettingsCopyCertificates; - static PtrSecTrustCopyAnchorCertificates ptrSecTrustCopyAnchorCertificates; -#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) static PtrCertOpenSystemStoreW ptrCertOpenSystemStoreW; static PtrCertFindCertificateInStore ptrCertFindCertificateInStore; static PtrCertCloseStore ptrCertCloseStore; diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index 29c47cd7c6..2173bf6ccc 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -46,6 +46,7 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op SOURCES += ssl/qsslcertificate_qt.cpp \ ssl/qsslkey_qt.cpp \ ssl/qsslkey_mac.cpp \ + ssl/qsslsocket_mac_shared.cpp \ ssl/qsslsocket_mac.cpp \ ssl/qsslellipticcurve_dummy.cpp } @@ -62,7 +63,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { ssl/qsslsocket_openssl.cpp \ ssl/qsslsocket_openssl_symbols.cpp -android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp + darwin:SOURCES += ssl/qsslsocket_mac_shared.cpp + + android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp # Add optional SSL libs # Static linking of OpenSSL with msvc: |