diff options
Diffstat (limited to 'src/network/kernel/qhostaddress.cpp')
-rw-r--r-- | src/network/kernel/qhostaddress.cpp | 128 |
1 files changed, 94 insertions, 34 deletions
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index b68f6adfff..58c0de1f3b 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtNetwork module of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** 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 @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** 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$ @@ -123,28 +123,41 @@ QHostAddressPrivate::QHostAddressPrivate() void QHostAddressPrivate::setAddress(quint32 a_) { a = a_; - //create mapped address + //create mapped address, except for a_ == 0 (any) memset(&a6, 0, sizeof(a6)); + if (a) { + a6[11] = 0xFF; + a6[10] = 0xFF; + } else { + a6[11] = 0; + a6[10] = 0; + } + int i; for (i=15; a_ != 0; i--) { a6[i] = a_ & 0xFF; a_ >>=8; } Q_ASSERT(i >= 11); - a6[11] = 0xFF; - a6[10] = 0xFF; protocol = QAbstractSocket::IPv4Protocol; isParsed = true; } -static bool parseMappedAddress(quint32& a, const Q_IPV6ADDR &a6) +/// parses v4-mapped addresses or the AnyIPv6 address and stores in \a a; +/// returns true if the address was one of those +static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6) { - int i; - for (i=0;i<10;i++) - if (a6[i]) return false; - for (;i<12;i++) - if (a6[i] != 0xFF) return false; - a=(a6[12] << 24) | (a6[13] << 16) | (a6[14] << 8) | a6[15]; + const uchar *ptr = a6.c; + if (qFromUnaligned<quint64>(ptr) != 0) + return false; + if (qFromBigEndian<quint32>(ptr + 8) == 0) { + // is it AnyIPv6? + a = 0; + return qFromBigEndian<quint32>(ptr + 12) == 0; + } + if (qFromBigEndian<quint32>(ptr + 8) != 0xFFFF) + return false; + a = qFromBigEndian<quint32>(ptr + 12); return true; } @@ -153,10 +166,8 @@ void QHostAddressPrivate::setAddress(const quint8 *a_) for (int i = 0; i < 16; i++) a6[i] = a_[i]; a = 0; - if (parseMappedAddress(a, a6)) - protocol = QAbstractSocket::IPv4Protocol; - else - protocol = QAbstractSocket::IPv6Protocol; + convertToIpv4(a, a6); + protocol = QAbstractSocket::IPv6Protocol; isParsed = true; } @@ -164,10 +175,8 @@ void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_) { a6 = a_; a = 0; - if (parseMappedAddress(a, a6)) - protocol = QAbstractSocket::IPv4Protocol; - else - protocol = QAbstractSocket::IPv6Protocol; + convertToIpv4(a, a6); + protocol = QAbstractSocket::IPv6Protocol; isParsed = true; } @@ -197,7 +206,6 @@ bool QHostAddressPrivate::parse() quint8 maybeIp6[16]; if (parseIp6(a, maybeIp6, &scopeId)) { setAddress(maybeIp6); - protocol = QAbstractSocket::IPv6Protocol; return true; } } @@ -205,7 +213,6 @@ bool QHostAddressPrivate::parse() quint32 maybeIp4 = 0; if (QIPAddressUtils::parseIp4(maybeIp4, a.constBegin(), a.constEnd())) { setAddress(maybeIp4); - protocol = QAbstractSocket::IPv4Protocol; return true; } @@ -408,6 +415,19 @@ QHostAddress::QHostAddress(quint8 *ip6Addr) } /*! + \since 5.5 + Constructs a host address object with the IPv6 address \a ip6Addr. + + \a ip6Addr must be a 16-byte array in network byte order (big + endian). +*/ +QHostAddress::QHostAddress(const quint8 *ip6Addr) + : d(new QHostAddressPrivate) +{ + setAddress(ip6Addr); +} + +/*! Constructs a host address object with the IPv6 address \a ip6Addr. */ QHostAddress::QHostAddress(const Q_IPV6ADDR &ip6Addr) @@ -442,9 +462,9 @@ QHostAddress::QHostAddress(const struct sockaddr *sockaddr) { #ifndef Q_OS_WINRT if (sockaddr->sa_family == AF_INET) - setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr)); + setAddress(htonl(((const sockaddr_in *)sockaddr)->sin_addr.s_addr)); else if (sockaddr->sa_family == AF_INET6) - setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr); + setAddress(((const qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr); #else Q_UNUSED(sockaddr) #endif @@ -568,6 +588,20 @@ void QHostAddress::setAddress(quint8 *ip6Addr) /*! \overload + \since 5.5 + + Set the IPv6 address specified by \a ip6Addr. + + \a ip6Addr must be an array of 16 bytes in network byte order + (high-order byte first). +*/ +void QHostAddress::setAddress(const quint8 *ip6Addr) +{ + d->setAddress(ip6Addr); +} + +/*! + \overload Set the IPv6 address specified by \a ip6Addr. */ @@ -603,9 +637,9 @@ void QHostAddress::setAddress(const struct sockaddr *sockaddr) #ifndef Q_OS_WINRT clear(); if (sockaddr->sa_family == AF_INET) - setAddress(htonl(((sockaddr_in *)sockaddr)->sin_addr.s_addr)); + setAddress(htonl(((const sockaddr_in *)sockaddr)->sin_addr.s_addr)); else if (sockaddr->sa_family == AF_INET6) - setAddress(((qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr); + setAddress(((const qt_sockaddr_in6 *)sockaddr)->sin6_addr.qt_s6_addr); #else Q_UNUSED(sockaddr) #endif @@ -627,7 +661,31 @@ void QHostAddress::setAddress(const struct sockaddr *sockaddr) */ quint32 QHostAddress::toIPv4Address() const { + return toIPv4Address(Q_NULLPTR); +} + +/*! + Returns the IPv4 address as a number. + + For example, if the address is 127.0.0.1, the returned value is + 2130706433 (i.e. 0x7f000001). + + This value is valid if the protocol() is + \l{QAbstractSocket::}{IPv4Protocol}, + or if the protocol is + \l{QAbstractSocket::}{IPv6Protocol}, + and the IPv6 address is an IPv4 mapped address. (RFC4291). In those + cases, \a ok will be set to true. Otherwise, it will be set to false. + + \sa toString() +*/ +quint32 QHostAddress::toIPv4Address(bool *ok) const +{ QT_ENSURE_PARSED(this); + quint32 dummy; + if (ok) + *ok = d->protocol == QAbstractSocket::IPv4Protocol || d->protocol == QAbstractSocket::AnyIPProtocol + || (d->protocol == QAbstractSocket::IPv6Protocol && convertToIpv4(dummy, d->a6)); return d->a; } @@ -1040,11 +1098,13 @@ bool QHostAddress::isLoopback() const #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QHostAddress &address) { + QDebugStateSaver saver(d); + d.resetFormat().nospace(); if (address == QHostAddress::Any) - d.maybeSpace() << "QHostAddress(QHostAddress::Any)"; + d << "QHostAddress(QHostAddress::Any)"; else - d.maybeSpace() << "QHostAddress(" << address.toString() << ')'; - return d.space(); + d << "QHostAddress(" << address.toString() << ')'; + return d; } #endif |