From 775d04f97ec1723c01c12f8faab05236686b9b05 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 24 Dec 2014 15:43:08 -0200 Subject: Add a QHostAddress::toIPv4Address overload taking a bool *ok This allows one to check whether the conversion is successful without checking for the return result, as the value of 0 represents the valid IPv4 address 0.0.0.0. Change-Id: I637fe55583f2255c85b0d955e5886b61494e0c7c Reviewed-by: Richard J. Moore --- src/network/kernel/qhostaddress.cpp | 24 +++++++++++ src/network/kernel/qhostaddress.h | 3 +- .../kernel/qhostaddress/tst_qhostaddress.cpp | 48 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 8d32711de3..9a993392e9 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -633,8 +633,32 @@ void QHostAddress::setAddress(const struct sockaddr *sockaddr) \sa toString() */ 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; } diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h index 93d64ff54a..de3a79278e 100644 --- a/src/network/kernel/qhostaddress.h +++ b/src/network/kernel/qhostaddress.h @@ -93,7 +93,8 @@ public: bool setAddress(const QString &address); QAbstractSocket::NetworkLayerProtocol protocol() const; - quint32 toIPv4Address() const; + quint32 toIPv4Address() const; // ### Qt6: merge with next overload + quint32 toIPv4Address(bool *ok) const; Q_IPV6ADDR toIPv6Address() const; QString toString() const; diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp index 60b96d38b7..ef24cbf3c8 100644 --- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp +++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp @@ -83,6 +83,8 @@ private slots: void isInSubnet(); void isLoopback_data(); void isLoopback(); + void convertv4v6_data(); + void convertv4v6(); }; QT_BEGIN_NAMESPACE @@ -662,5 +664,51 @@ void tst_QHostAddress::isLoopback() QCOMPARE(address.isLoopback(), result); } +void tst_QHostAddress::convertv4v6_data() +{ + QTest::addColumn("source"); + QTest::addColumn("protocol"); + QTest::addColumn("result"); + + QTest::newRow("any-to-v4") << QHostAddress(QHostAddress::Any) << 4 << QHostAddress(QHostAddress::AnyIPv4); + QTest::newRow("any-to-v6") << QHostAddress(QHostAddress::Any) << 6 << QHostAddress(QHostAddress::AnyIPv6); + QTest::newRow("anyv4-to-v6") << QHostAddress(QHostAddress::AnyIPv4) << 6 << QHostAddress(QHostAddress::AnyIPv6); + QTest::newRow("anyv6-to-v4") << QHostAddress(QHostAddress::AnyIPv6) << 4 << QHostAddress(QHostAddress::AnyIPv4); + + QTest::newRow("v4mapped-to-v4") << QHostAddress("::ffff:192.0.2.1") << 4 << QHostAddress("192.0.2.1"); + QTest::newRow("v4-to-v4mapped") << QHostAddress("192.0.2.1") << 6 << QHostAddress("::ffff:192.0.2.1"); + + // we won't convert 127.0.0.1 to ::1 or vice-versa: + // you can connect to a v4 server socket with ::ffff:127.0.0.1, but not with ::1 + QTest::newRow("localhost-to-v4mapped") << QHostAddress(QHostAddress::LocalHost) << 6 << QHostAddress("::ffff:127.0.0.1"); + QTest::newRow("v4mapped-to-localhost") << QHostAddress("::ffff:127.0.0.1") << 4 << QHostAddress(QHostAddress::LocalHost); + + // in turn, that means localhost6 doesn't convert to v4 + QTest::newRow("localhost6-to-v4") << QHostAddress(QHostAddress::LocalHostIPv6) << 4 << QHostAddress(); + + // some other v6 addresses that won't convert to v4 + QTest::newRow("v4compat-to-v4") << QHostAddress("::192.0.2.1") << 4 << QHostAddress(); + QTest::newRow("localhostv4compat-to-v4") << QHostAddress("::127.0.0.1") << 4 << QHostAddress(); + QTest::newRow("v6global-to-v4") << QHostAddress("2001:db8::1") << 4 << QHostAddress(); + QTest::newRow("v6multicast-to-v4") << QHostAddress("ff02::1") << 4 << QHostAddress(); +} + +void tst_QHostAddress::convertv4v6() +{ + QFETCH(QHostAddress, source); + QFETCH(int, protocol); + QFETCH(QHostAddress, result); + + if (protocol == 4) { + bool ok; + quint32 v4 = source.toIPv4Address(&ok); + QCOMPARE(ok, result.protocol() == QAbstractSocket::IPv4Protocol); + if (ok) + QCOMPARE(QHostAddress(v4), result); + } else if (protocol == 6) { + QCOMPARE(QHostAddress(source.toIPv6Address()), result); + } +} + QTEST_MAIN(tst_QHostAddress) #include "tst_qhostaddress.moc" -- cgit v1.2.3