diff options
Diffstat (limited to 'src/network/kernel/qhostaddress.cpp')
-rw-r--r-- | src/network/kernel/qhostaddress.cpp | 138 |
1 files changed, 80 insertions, 58 deletions
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 58c0de1f3b..d775007f46 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -46,6 +46,9 @@ #ifndef QT_NO_DATASTREAM #include <qdatastream.h> #endif +#ifdef __SSE2__ +# include <private/qsimd_p.h> +#endif #ifdef QT_LINUXBASE # include <arpa/inet.h> @@ -106,7 +109,11 @@ public: QString scopeId; quint32 a; // IPv4 address - Q_IPV6ADDR a6; // IPv6 address + union { + Q_IPV6ADDR a6; // IPv6 address + struct { quint64 c[2]; } a6_64; + struct { quint32 c[4]; } a6_32; + }; QAbstractSocket::NetworkLayerProtocol protocol; bool isParsed; @@ -123,24 +130,17 @@ QHostAddressPrivate::QHostAddressPrivate() void QHostAddressPrivate::setAddress(quint32 a_) { a = a_; + protocol = QAbstractSocket::IPv4Protocol; + isParsed = true; + //create mapped address, except for a_ == 0 (any) - memset(&a6, 0, sizeof(a6)); + a6_64.c[0] = 0; if (a) { - a6[11] = 0xFF; - a6[10] = 0xFF; + a6_32.c[2] = qToBigEndian(0xffff); + a6_32.c[3] = qToBigEndian(a); } else { - a6[11] = 0; - a6[10] = 0; + a6_64.c[1] = 0; } - - int i; - for (i=15; a_ != 0; i--) { - a6[i] = a_ & 0xFF; - a_ >>=8; - } - Q_ASSERT(i >= 11); - protocol = QAbstractSocket::IPv4Protocol; - isParsed = true; } /// parses v4-mapped addresses or the AnyIPv6 address and stores in \a a; @@ -163,21 +163,16 @@ static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6) void QHostAddressPrivate::setAddress(const quint8 *a_) { - for (int i = 0; i < 16; i++) - a6[i] = a_[i]; - a = 0; - convertToIpv4(a, a6); protocol = QAbstractSocket::IPv6Protocol; isParsed = true; + memcpy(a6.c, a_, sizeof(a6)); + a = 0; + convertToIpv4(a, a6); } void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_) { - a6 = a_; - a = 0; - convertToIpv4(a, a6); - protocol = QAbstractSocket::IPv6Protocol; - isParsed = true; + setAddress(a_.c); } static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, QString *scopeId) @@ -193,7 +188,7 @@ static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, return QIPAddressUtils::parseIp6(addr, tmp.constBegin(), tmp.constEnd()) == 0; } -bool QHostAddressPrivate::parse() +Q_NEVER_INLINE bool QHostAddressPrivate::parse() { isParsed = true; protocol = QAbstractSocket::UnknownNetworkLayerProtocol; @@ -384,7 +379,7 @@ void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol prot \value Any The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces. */ -/*! Constructs a host address object with the IP address 0.0.0.0. +/*! Constructs a null host address object, i.e. an address which is not valid for any host or interface. \sa clear() */ @@ -486,31 +481,35 @@ QHostAddress::QHostAddress(SpecialAddress address) { Q_IPV6ADDR ip6; memset(&ip6, 0, sizeof ip6); + quint32 ip4 = INADDR_ANY; switch (address) { case Null: - break; + return; + case Broadcast: - d->setAddress(quint32(-1)); + ip4 = INADDR_BROADCAST; break; case LocalHost: - d->setAddress(0x7f000001); - break; - case LocalHostIPv6: - ip6[15] = 1; - d->setAddress(ip6); + ip4 = INADDR_LOOPBACK; break; case AnyIPv4: - setAddress(0u); break; + + case LocalHostIPv6: + ip6[15] = 1; + // fall through case AnyIPv6: d->setAddress(ip6); - break; + return; + case Any: - d->clear(); d->protocol = QAbstractSocket::AnyIPProtocol; - break; + return; } + + // common IPv4 part + d->setAddress(ip4); } /*! @@ -775,11 +774,6 @@ QString QHostAddress::toString() const on your host. Link-local addresses ("fe80...") are generated from the MAC address of the local network adaptor, and are not guaranteed to be unique. - \li Site-local: Addresses that are local to the site / private network - (e.g., the company intranet). Site-local addresses ("fec0...") are - usually distributed by the site router, and are not guaranteed to be - unique outside of the local site. - \li Global: For globally routable addresses, such as public servers on the Internet. @@ -790,7 +784,7 @@ QString QHostAddress::toString() const usually the same as the interface name (e.g., "eth0", "en1") or number (e.g., "1", "2"). - \sa setScopeId() + \sa setScopeId(), QNetworkInterface, QNetworkInterface::interfaceFromName */ QString QHostAddress::scopeId() const { @@ -801,8 +795,14 @@ QString QHostAddress::scopeId() const /*! \since 4.1 - Sets the IPv6 scope ID of the address to \a id. If the address - protocol is not IPv6, this function does nothing. + Sets the IPv6 scope ID of the address to \a id. If the address protocol is + not IPv6, this function does nothing. The scope ID may be set as an + interface name (such as "eth0" or "en1") or as an integer representing the + interface index. If \a id is an interface name, QtNetwork will convert to + an interface index using QNetworkInterface::interfaceIndexFromName() before + calling the operating system networking functions. + + \sa scopeId(), QNetworkInterface, QNetworkInterface::interfaceFromName */ void QHostAddress::setScopeId(const QString &id) { @@ -836,34 +836,36 @@ bool QHostAddress::operator==(const QHostAddress &other) const bool QHostAddress::operator ==(SpecialAddress other) const { QT_ENSURE_PARSED(this); + quint32 ip4 = INADDR_ANY; switch (other) { case Null: return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol; case Broadcast: - return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_BROADCAST; + ip4 = INADDR_BROADCAST; + break; case LocalHost: - return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_LOOPBACK; + ip4 = INADDR_LOOPBACK; + break; case Any: return d->protocol == QAbstractSocket::AnyIPProtocol; case AnyIPv4: - return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_ANY; + break; case LocalHostIPv6: case AnyIPv6: if (d->protocol == QAbstractSocket::IPv6Protocol) { - Q_IPV6ADDR ip6 = { { 0 } }; - ip6[15] = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any - return memcmp(&d->a6, &ip6, sizeof ip6) == 0; + quint64 second = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any + return d->a6_64.c[0] == 0 && d->a6_64.c[1] == qToBigEndian(second); } return false; } - Q_UNREACHABLE(); - return false; + // common IPv4 part + return d->protocol == QAbstractSocket::IPv4Protocol && d->a == ip4; } /*! @@ -1085,16 +1087,36 @@ bool QHostAddress::isLoopback() const if ((d->a & 0xFF000000) == 0x7F000000) return true; // v4 range (including IPv6 wrapped IPv4 addresses) if (d->protocol == QAbstractSocket::IPv6Protocol) { - if (d->a6.c[15] != 1) +#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; - for (int i = 0; i < 15; i++) - if (d->a6[i] != 0) - return false; +#endif return true; } return false; } +/*! + \since 5.6 + + Returns \c true if the address is an IPv4 or IPv6 multicast address, \c + false otherwise. +*/ +bool QHostAddress::isMulticast() const +{ + QT_ENSURE_PARSED(this); + 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; +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const QHostAddress &address) { @@ -1112,7 +1134,7 @@ uint qHash(const QHostAddress &key, uint seed) { // both lines might throw QT_ENSURE_PARSED(&key); - return qHash(QByteArray::fromRawData(reinterpret_cast<const char *>(key.d->a6.c), 16), seed); + return qHashBits(key.d->a6.c, 16, seed); } #ifndef QT_NO_DATASTREAM |