summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2011-10-14 17:12:34 +0200
committerQt by Nokia <qt-info@nokia.com>2012-03-28 16:31:34 +0200
commit826c0723c1dbca9742f3b8b0cb6d31df21f17664 (patch)
treee0fd746936980f000ec120aaa42f903112325e14
parent70db6233e7685e1b76e038f9baf25d1c70baa9aa (diff)
Add support for IPv6 parsing and reconstructing the address
Similarly, only test against the libc function on Linux, as other OS sometimes have different behaviour. Change-Id: I9b8ef9a3d660a59882396d695202865ca307e528 Reviewed-by: João Abecasis <joao.abecasis@nokia.com> Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
-rw-r--r--src/corelib/io/qipaddress.cpp217
-rw-r--r--src/corelib/io/qipaddress_p.h3
-rw-r--r--tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp285
3 files changed, 503 insertions, 2 deletions
diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp
index b8871fe8b9..e996c8665c 100644
--- a/src/corelib/io/qipaddress.cpp
+++ b/src/corelib/io/qipaddress.cpp
@@ -71,6 +71,7 @@ static bool checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end)
return true;
}
+static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptLeadingZero);
bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end)
{
Q_ASSERT(begin != end);
@@ -78,10 +79,19 @@ bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end)
if (!checkedToAscii(buffer, begin, end))
return false;
- int dotCount = 0;
- address = 0;
const char *ptr = buffer.data();
+ return parseIp4Internal(address, ptr, true);
+}
+
+static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptLeadingZero)
+{
+ address = 0;
+ int dotCount = 0;
while (dotCount < 4) {
+ if (!acceptLeadingZero && *ptr == '0' &&
+ ptr[1] != '.' && ptr[1] != '\0')
+ return false;
+
const char *endptr;
bool ok;
quint64 ll = qstrtoull(ptr, &endptr, 0, &ok);
@@ -127,5 +137,208 @@ void toString(QString &appendTo, IPv4Address address)
% number(address);
}
+bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
+{
+ Q_ASSERT(begin != end);
+ Buffer buffer;
+ if (!checkedToAscii(buffer, begin, end))
+ return false;
+
+ const char *ptr = buffer.data();
+
+ // count the colons
+ int colonCount = 0;
+ int dotCount = 0;
+ while (*ptr) {
+ if (*ptr == ':')
+ ++colonCount;
+ if (*ptr == '.')
+ ++dotCount;
+ ++ptr;
+ }
+ // IPv4-in-IPv6 addresses are stricter in what they accept
+ if (dotCount != 0 && dotCount != 3)
+ return false;
+
+ memset(address, 0, sizeof address);
+ if (colonCount == 2 && end - begin == 2) // "::"
+ return true;
+
+ // if there's a double colon ("::"), this is how many zeroes it means
+ int zeroWordsToFill;
+ ptr = buffer.data();
+
+ // there are two cases where 8 colons are allowed: at the ends
+ // so test that before the colon-count test
+ if ((ptr[0] == ':' && ptr[1] == ':') ||
+ (ptr[end - begin - 2] == ':' && ptr[end - begin - 1] == ':')) {
+ zeroWordsToFill = 9 - colonCount;
+ } else if (colonCount < 2 || colonCount > 7) {
+ return false;
+ } else {
+ zeroWordsToFill = 8 - colonCount;
+ }
+ if (dotCount)
+ --zeroWordsToFill;
+
+ int pos = 0;
+ while (pos < 15) {
+ const char *endptr;
+ bool ok;
+ quint64 ll = qstrtoull(ptr, &endptr, 16, &ok);
+ quint16 x = ll;
+
+ if (ptr == endptr) {
+ // empty field, we hope it's "::"
+ if (zeroWordsToFill < 1)
+ return false;
+ if (pos == 0 || pos == colonCount * 2) {
+ if (ptr[0] == '\0' || ptr[1] != ':')
+ return false;
+ ++ptr;
+ }
+ pos += zeroWordsToFill * 2;
+ zeroWordsToFill = 0;
+ ++ptr;
+ continue;
+ }
+ if (!ok || ll != x)
+ return false;
+
+ if (*endptr == '.') {
+ // this could be an IPv4 address
+ // it's only valid in the last element
+ if (pos != 12)
+ return false;
+
+ IPv4Address ip4;
+ if (!parseIp4Internal(ip4, ptr, false))
+ return false;
+
+ address[12] = ip4 >> 24;
+ address[13] = ip4 >> 16;
+ address[14] = ip4 >> 8;
+ address[15] = ip4;
+ return true;
+ }
+
+ address[pos++] = x >> 8;
+ address[pos++] = x & 0xff;
+
+ if (*endptr == '\0')
+ break;
+ if (*endptr != ':')
+ return false;
+ ptr = endptr + 1;
+ }
+ return pos == 16;
+}
+
+static inline QChar toHex(uchar c)
+{
+ return ushort(c > 9 ? c + 'a' - 0xA : c + '0');
+}
+
+void toString(QString &appendTo, IPv6Address address)
+{
+ // the longest IPv6 address possible is:
+ // "1111:2222:3333:4444:5555:6666:255.255.255.255"
+ // however, this function never generates that. The longest it does
+ // generate without an IPv4 address is:
+ // "1111:2222:3333:4444:5555:6666:7777:8888"
+ // and the longest with an IPv4 address is:
+ // "::ffff:255.255.255.255"
+ static const int Ip6AddressMaxLen = sizeof "1111:2222:3333:4444:5555:6666:7777:8888";
+ static const int Ip6WithIp4AddressMaxLen = sizeof "::ffff:255.255.255.255";
+
+ // check for the special cases
+ const quint64 zeroes[] = { 0, 0 };
+ bool embeddedIp4 = false;
+
+ // we consider embedded IPv4 for:
+ // ::ffff:x.x.x.x
+ // ::x.x.x.y except if the x are 0 too
+ if (memcmp(address, zeroes, 10) == 0) {
+ if (address[10] == 0xff && address[11] == 0xff) {
+ embeddedIp4 = true;
+ } else if (address[10] == 0 && address[11] == 0) {
+ if (address[12] != 0 || address[13] != 0 || address[14] != 0) {
+ embeddedIp4 = true;
+ } else if (address[15] == 0) {
+ appendTo.append(QLatin1String("::"));
+ return;
+ }
+ }
+ }
+
+ // QString::reserve doesn't shrink, so it's fine to us
+ appendTo.reserve(appendTo.size() +
+ embeddedIp4 ? Ip6WithIp4AddressMaxLen : Ip6AddressMaxLen);
+
+ // for finding where to place the "::"
+ int zeroRunLength = 0; // in octets
+ int zeroRunOffset = 0; // in octets
+ for (int i = 0; i < 16; i += 2) {
+ if (address[i] == 0 && address[i + 1] == 0) {
+ // found a zero, scan forward to see how many more there are
+ int j;
+ for (j = i; j < 16; j += 2) {
+ if (address[j] != 0 || address[j+1] != 0)
+ break;
+ }
+
+ if (j - i > zeroRunLength) {
+ zeroRunLength = j - i;
+ zeroRunOffset = i;
+ i = j;
+ }
+ }
+ }
+
+ const QChar colon = ushort(':');
+ if (zeroRunLength < 4)
+ zeroRunOffset = -1;
+ else if (zeroRunOffset == 0)
+ appendTo.append(colon);
+
+ for (int i = 0; i < 16; i += 2) {
+ if (i == zeroRunOffset) {
+ appendTo.append(colon);
+ i += zeroRunLength - 2;
+ continue;
+ }
+
+ if (i == 12 && embeddedIp4) {
+ IPv4Address ip4 = address[12] << 24 |
+ address[13] << 16 |
+ address[14] << 8 |
+ address[15];
+ toString(appendTo, ip4);
+ return;
+ }
+
+ if (address[i]) {
+ if (address[i] >> 4) {
+ appendTo.append(toHex(address[i] >> 4));
+ appendTo.append(toHex(address[i] & 0xf));
+ appendTo.append(toHex(address[i + 1] >> 4));
+ appendTo.append(toHex(address[i + 1] & 0xf));
+ } else if (address[i] & 0xf) {
+ appendTo.append(toHex(address[i] & 0xf));
+ appendTo.append(toHex(address[i + 1] >> 4));
+ appendTo.append(toHex(address[i + 1] & 0xf));
+ }
+ } else if (address[i + 1] >> 4) {
+ appendTo.append(toHex(address[i + 1] >> 4));
+ appendTo.append(toHex(address[i + 1] & 0xf));
+ } else {
+ appendTo.append(toHex(address[i + 1] & 0xf));
+ }
+
+ if (i != 14)
+ appendTo.append(colon);
+ }
+}
+
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qipaddress_p.h b/src/corelib/io/qipaddress_p.h
index f3bcf76424..834f9557f3 100644
--- a/src/corelib/io/qipaddress_p.h
+++ b/src/corelib/io/qipaddress_p.h
@@ -60,9 +60,12 @@ QT_BEGIN_NAMESPACE
namespace QIPAddressUtils {
typedef quint32 IPv4Address;
+typedef quint8 IPv6Address[16];
Q_CORE_EXPORT bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end);
+Q_CORE_EXPORT bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end);
Q_CORE_EXPORT void toString(QString &appendTo, IPv4Address address);
+Q_CORE_EXPORT void toString(QString &appendTo, IPv6Address address);
} // namespace
diff --git a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp
index 73cbbdea0e..bad18fabef 100644
--- a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp
+++ b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp
@@ -60,7 +60,65 @@ private Q_SLOTS:
void invalidParseIp4();
void ip4ToString_data();
void ip4ToString();
+
+ void parseIp6_data();
+ void parseIp6();
+ void invalidParseIp6_data();
+ void invalidParseIp6();
+ void ip6ToString_data();
+ void ip6ToString();
+};
+
+struct Ip6
+{
+ QIPAddressUtils::IPv6Address u8;
+ Ip6() { *this = Ip6(0,0,0,0, 0,0,0,0); }
+ Ip6(quint16 p1, quint16 p2, quint16 p3, quint16 p4,
+ quint16 p5, quint16 p6, quint16 p7, quint16 p8)
+ {
+ u8[0] = p1 >> 8;
+ u8[2] = p2 >> 8;
+ u8[4] = p3 >> 8;
+ u8[6] = p4 >> 8;
+ u8[8] = p5 >> 8;
+ u8[10] = p6 >> 8;
+ u8[12] = p7 >> 8;
+ u8[14] = p8 >> 8;
+
+ u8[1] = p1 & 0xff;
+ u8[3] = p2 & 0xff;
+ u8[5] = p3 & 0xff;
+ u8[7] = p4 & 0xff;
+ u8[9] = p5 & 0xff;
+ u8[11] = p6 & 0xff;
+ u8[13] = p7 & 0xff;
+ u8[15] = p8 & 0xff;
+ }
+
+ bool operator==(const Ip6 &other) const
+ { return memcmp(u8, other.u8, sizeof u8) == 0; }
};
+Q_DECLARE_METATYPE(Ip6)
+
+QT_BEGIN_NAMESPACE
+namespace QTest {
+ template<>
+ char *toString(const Ip6 &ip6)
+ {
+ char buf[sizeof "1111:2222:3333:4444:5555:6666:7777:8888" + 2];
+ sprintf(buf, "%x:%x:%x:%x:%x:%x:%x:%x",
+ ip6.u8[0] << 8 | ip6.u8[1],
+ ip6.u8[2] << 8 | ip6.u8[3],
+ ip6.u8[4] << 8 | ip6.u8[5],
+ ip6.u8[6] << 8 | ip6.u8[7],
+ ip6.u8[8] << 8 | ip6.u8[9],
+ ip6.u8[10] << 8 | ip6.u8[11],
+ ip6.u8[12] << 8 | ip6.u8[13],
+ ip6.u8[14] << 8 | ip6.u8[15]);
+ return strdup(buf);
+ }
+}
+QT_END_NAMESPACE
void tst_QIpAddress::parseIp4_data()
{
@@ -213,6 +271,233 @@ void tst_QIpAddress::ip4ToString()
QCOMPARE(result, expected);
}
+void tst_QIpAddress::parseIp6_data()
+{
+ qRegisterMetaType<Ip6>();
+ QTest::addColumn<QString>("address");
+ QTest::addColumn<Ip6>("expected");
+
+ // 7 colons, no ::
+ QTest::newRow("0:0:0:0:0:0:0:0") << "0:0:0:0:0:0:0:0" << Ip6(0,0,0,0,0,0,0,0);
+ QTest::newRow("0:0:0:0:0:0:0:1") << "0:0:0:0:0:0:0:1" << Ip6(0,0,0,0,0,0,0,1);
+ QTest::newRow("0:0:0:0:0:0:1:1") << "0:0:0:0:0:0:1:1" << Ip6(0,0,0,0,0,0,1,1);
+ QTest::newRow("0:0:0:0:0:0:0:103") << "0:0:0:0:0:0:0:103" << Ip6(0,0,0,0,0,0,0,0x103);
+ QTest::newRow("1:2:3:4:5:6:7:8") << "1:2:3:4:5:6:7:8" << Ip6(1,2,3,4,5,6,7,8);
+ QTest::newRow("ffee:ddcc:bbaa:9988:7766:5544:3322:1100")
+ << "ffee:ddcc:bbaa:9988:7766:5544:3322:1100"
+ << Ip6(0xffee, 0xddcc, 0xbbaa, 0x9988, 0x7766, 0x5544, 0x3322, 0x1100);
+
+ // too many zeroes
+ QTest::newRow("0:0:0:0:0:0:0:00103") << "0:0:0:0:0:0:0:00103" << Ip6(0,0,0,0,0,0,0,0x103);
+
+ // double-colon
+ QTest::newRow("::1:2:3:4:5:6:7") << "::1:2:3:4:5:6:7" << Ip6(0,1,2,3,4,5,6,7);
+ QTest::newRow("1:2:3:4:5:6:7::") << "1:2:3:4:5:6:7::" << Ip6(1,2,3,4,5,6,7,0);
+
+ QTest::newRow("1::2:3:4:5:6:7") << "1::2:3:4:5:6:7" << Ip6(1,0,2,3,4,5,6,7);
+ QTest::newRow("1:2::3:4:5:6:7") << "1:2::3:4:5:6:7" << Ip6(1,2,0,3,4,5,6,7);
+ QTest::newRow("1:2:3::4:5:6:7") << "1:2:3::4:5:6:7" << Ip6(1,2,3,0,4,5,6,7);
+ QTest::newRow("1:2:3:4::5:6:7") << "1:2:3:4::5:6:7" << Ip6(1,2,3,4,0,5,6,7);
+ QTest::newRow("1:2:3:4:5::6:7") << "1:2:3:4:5::6:7" << Ip6(1,2,3,4,5,0,6,7);
+ QTest::newRow("1:2:3:4:5:6::7") << "1:2:3:4:5:6::7" << Ip6(1,2,3,4,5,6,0,7);
+
+ QTest::newRow("::1:2:3:4:5:6") << "::1:2:3:4:5:6" << Ip6(0,0,1,2,3,4,5,6);
+ QTest::newRow("1:2:3:4:5:6::") << "1:2:3:4:5:6::" << Ip6(1,2,3,4,5,6,0,0);
+
+ QTest::newRow("1::2:3:4:5:6") << "1::2:3:4:5:6" << Ip6(1,0,0,2,3,4,5,6);
+ QTest::newRow("1:2::3:4:5:6") << "1:2::3:4:5:6" << Ip6(1,2,0,0,3,4,5,6);
+ QTest::newRow("1:2:3::4:5:6") << "1:2:3::4:5:6" << Ip6(1,2,3,0,0,4,5,6);
+ QTest::newRow("1:2:3:4::5:6") << "1:2:3:4::5:6" << Ip6(1,2,3,4,0,0,5,6);
+ QTest::newRow("1:2:3:4:5::6") << "1:2:3:4:5::6" << Ip6(1,2,3,4,5,0,0,6);
+
+ QTest::newRow("::1:2:3:4:5") << "::1:2:3:4:5" << Ip6(0,0,0,1,2,3,4,5);
+ QTest::newRow("1:2:3:4:5::") << "1:2:3:4:5::" << Ip6(1,2,3,4,5,0,0,0);
+
+ QTest::newRow("1::2:3:4:5") << "1::2:3:4:5" << Ip6(1,0,0,0,2,3,4,5);
+ QTest::newRow("1:2::3:4:5") << "1:2::3:4:5" << Ip6(1,2,0,0,0,3,4,5);
+ QTest::newRow("1:2:3::4:5") << "1:2:3::4:5" << Ip6(1,2,3,0,0,0,4,5);
+ QTest::newRow("1:2:3:4::5") << "1:2:3:4::5" << Ip6(1,2,3,4,0,0,0,5);
+
+ QTest::newRow("::1:2:3:4") << "::1:2:3:4" << Ip6(0,0,0,0,1,2,3,4);
+ QTest::newRow("1:2:3:4::") << "1:2:3:4::" << Ip6(1,2,3,4,0,0,0,0);
+
+ QTest::newRow("1::2:3:4") << "1::2:3:4" << Ip6(1,0,0,0,0,2,3,4);
+ QTest::newRow("1:2::3:4") << "1:2::3:4" << Ip6(1,2,0,0,0,0,3,4);
+ QTest::newRow("1:2:3::4") << "1:2:3::4" << Ip6(1,2,3,0,0,0,0,4);
+
+ QTest::newRow("::1:2:3") << "::1:2:3" << Ip6(0,0,0,0,0,1,2,3);
+ QTest::newRow("1:2:3::") << "1:2:3::" << Ip6(1,2,3,0,0,0,0,0);
+
+ QTest::newRow("1::2:3") << "1::2:3" << Ip6(1,0,0,0,0,0,2,3);
+ QTest::newRow("1:2::3") << "1:2::3" << Ip6(1,2,0,0,0,0,0,3);
+
+ QTest::newRow("::1:2") << "::1:2" << Ip6(0,0,0,0,0,0,1,2);
+ QTest::newRow("1:2::") << "1:2::" << Ip6(1,2,0,0,0,0,0,0);
+
+ QTest::newRow("1::2") << "1::2" << Ip6(1,0,0,0,0,0,0,2);
+
+ QTest::newRow("::1") << "::1" << Ip6(0,0,0,0,0,0,0,1);
+ QTest::newRow("1::") << "1::" << Ip6(1,0,0,0,0,0,0,0);
+
+ QTest::newRow("::") << "::" << Ip6(0,0,0,0,0,0,0,0);
+
+ // embedded IPv4
+ QTest::newRow("1:2:3:4:5:6:10.0.16.1") << "1:2:3:4:5:6:10.0.16.1" << Ip6(1,2,3,4,5,6,0xa00,0x1001);
+ QTest::newRow("1::10.0.16.1") << "1::10.0.16.1" << Ip6(1,0,0,0,0,0,0xa00,0x1001);
+ QTest::newRow("::10.0.16.1") << "::10.0.16.1" << Ip6(0,0,0,0,0,0,0xa00,0x1001);
+ QTest::newRow("::0.0.0.0") << "::0.0.0.0" << Ip6(0,0,0,0,0,0,0,0);
+}
+
+void tst_QIpAddress::parseIp6()
+{
+ QFETCH(QString, address);
+ QFETCH(Ip6, expected);
+
+#if defined(__GLIBC__) && defined(AF_INET6)
+ Ip6 inet_result;
+ bool inet_ok = inet_pton(AF_INET6, address.toLatin1(), &inet_result.u8);
+ QVERIFY(inet_ok);
+ QCOMPARE(inet_result, expected);
+#endif
+
+ Ip6 result;
+ bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd());
+ QVERIFY(ok);
+ QCOMPARE(result, expected);
+}
+
+void tst_QIpAddress::invalidParseIp6_data()
+{
+ QTest::addColumn<QString>("address");
+
+ // too many colons
+ QTest::newRow("0:0:0:0::0:0:0:0") << "0:0:0:0::0:0:0:0";
+ QTest::newRow("0:::") << "0:::"; QTest::newRow(":::0") << ":::0";
+ QTest::newRow("16:::::::::::::::::::::::") << "16:::::::::::::::::::::::";
+
+ // non-hex
+ QTest::newRow("a:b:c:d:e:f:g:h") << "a:b:c:d:e:f:g:h";
+
+ // too big number
+ QTest::newRow("0:0:0:0:0:0:0:10103") << "0:0:0:0:0:0:0:10103";
+
+ // too short
+ QTest::newRow("0:0:0:0:0:0:0:") << "0:0:0:0:0:0:0:";
+ QTest::newRow("0:0:0:0:0:0:0") << "0:0:0:0:0:0:0";
+ QTest::newRow("0:0:0:0:0:0:") << "0:0:0:0:0:0:";
+ QTest::newRow("0:0:0:0:0:0") << "0:0:0:0:0:0";
+ QTest::newRow("0:0:0:0:0:") << "0:0:0:0:0:";
+ QTest::newRow("0:0:0:0:0") << "0:0:0:0:0";
+ QTest::newRow("0:0:0:0:") << "0:0:0:0:";
+ QTest::newRow("0:0:0:0") << "0:0:0:0";
+ QTest::newRow("0:0:0:") << "0:0:0:";
+ QTest::newRow("0:0:0") << "0:0:0";
+ QTest::newRow("0:0:") << "0:0:";
+ QTest::newRow("0:0") << "0:0";
+ QTest::newRow("0:") << "0:";
+ QTest::newRow("0") << "0";
+ QTest::newRow(":0") << ":0";
+ QTest::newRow(":0:0") << ":0:0";
+ QTest::newRow(":0:0:0") << ":0:0:0";
+ QTest::newRow(":0:0:0:0") << ":0:0:0:0";
+ QTest::newRow(":0:0:0:0:0") << ":0:0:0:0:0";
+ QTest::newRow(":0:0:0:0:0:0") << ":0:0:0:0:0:0";
+ QTest::newRow(":0:0:0:0:0:0:0") << ":0:0:0:0:0:0:0";
+
+ // IPv4
+ QTest::newRow("1.2.3.4") << "1.2.3.4";
+
+ // embedded IPv4 in the wrong position
+ QTest::newRow("1.2.3.4::") << "1.2.3.4::";
+ QTest::newRow("f:1.2.3.4::") << "f:1.2.3.4::";
+ QTest::newRow("f:e:d:c:b:1.2.3.4:0") << "f:e:d:c:b:1.2.3.4:0";
+
+ // bad embedded IPv4
+ QTest::newRow("::1.2.3") << "::1.2.3";
+ QTest::newRow("::1.2.257") << "::1.2.257";
+ QTest::newRow("::1.2") << "::1.2";
+ QTest::newRow("::0250.0x10101") << "::0250.0x10101";
+ QTest::newRow("::1.2.3.0250") << "::1.2.3.0250";
+ QTest::newRow("::1.2.3.0xff") << "::1.2.3.0xff";
+ QTest::newRow("::1.2.3.07") << "::1.2.3.07";
+ QTest::newRow("::1.2.3.010") << "::1.2.3.010";
+
+ // separated by something else
+ QTest::newRow("1.2.3.4.5.6.7.8") << "1.2.3.4.5.6.7.8";
+ QTest::newRow("1,2,3,4,5,6,7,8") << "1,2,3,4,5,6,7,8";
+ QTest::newRow("1..2") << "1..2";
+ QTest::newRow("1:.2") << "1:.2";
+ QTest::newRow("1.:2") << "1.:2";
+}
+
+void tst_QIpAddress::invalidParseIp6()
+{
+ QFETCH(QString, address);
+
+#if defined(__GLIBC__) && defined(AF_INET6)
+ Ip6 inet_result;
+ bool inet_ok = inet_pton(AF_INET6, address.toLatin1(), &inet_result.u8);
+ QVERIFY(!inet_ok);
+#endif
+
+ Ip6 result;
+ bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd());
+ QVERIFY(!ok);
+}
+
+void tst_QIpAddress::ip6ToString_data()
+{
+ qRegisterMetaType<Ip6>();
+ QTest::addColumn<Ip6>("ip");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("1:2:3:4:5:6:7:8") << Ip6(1,2,3,4,5,6,7,8) << "1:2:3:4:5:6:7:8";
+ QTest::newRow("1:2:3:4:5:6:7:88") << Ip6(1,2,3,4,5,6,7,0x88) << "1:2:3:4:5:6:7:88";
+ QTest::newRow("1:2:3:4:5:6:7:888") << Ip6(1,2,3,4,5,6,7,0x888) << "1:2:3:4:5:6:7:888";
+ QTest::newRow("1:2:3:4:5:6:7:8888") << Ip6(1,2,3,4,5,6,7,0x8888) << "1:2:3:4:5:6:7:8888";
+ QTest::newRow("1:2:3:4:5:6:7:8880") << Ip6(1,2,3,4,5,6,7,0x8880) << "1:2:3:4:5:6:7:8880";
+ QTest::newRow("1:2:3:4:5:6:7:8808") << Ip6(1,2,3,4,5,6,7,0x8808) << "1:2:3:4:5:6:7:8808";
+ QTest::newRow("1:2:3:4:5:6:7:8088") << Ip6(1,2,3,4,5,6,7,0x8088) << "1:2:3:4:5:6:7:8088";
+
+ QTest::newRow("1:2:3:4:5:6:7:0") << Ip6(1,2,3,4,5,6,7,0) << "1:2:3:4:5:6:7:0";
+ QTest::newRow("0:1:2:3:4:5:6:7") << Ip6(0,1,2,3,4,5,6,7) << "0:1:2:3:4:5:6:7";
+
+ QTest::newRow("1:2:3:4:5:6::") << Ip6(1,2,3,4,5,6,0,0) << "1:2:3:4:5:6::";
+ QTest::newRow("::1:2:3:4:5:6") << Ip6(0,0,1,2,3,4,5,6) << "::1:2:3:4:5:6";
+ QTest::newRow("1:0:0:2::3") << Ip6(1,0,0,2,0,0,0,3) << "1:0:0:2::3";
+ QTest::newRow("1:::2:0:0:3") << Ip6(1,0,0,0,2,0,0,3) << "1::2:0:0:3";
+ QTest::newRow("1::2:0:0:0") << Ip6(1,0,0,0,2,0,0,0) << "1::2:0:0:0";
+ QTest::newRow("0:0:0:1::") << Ip6(0,0,0,1,0,0,0,0) << "0:0:0:1::";
+ QTest::newRow("::1:0:0:0") << Ip6(0,0,0,0,1,0,0,0) << "::1:0:0:0";
+ QTest::newRow("ff02::1") << Ip6(0xff02,0,0,0,0,0,0,1) << "ff02::1";
+ QTest::newRow("1::1") << Ip6(1,0,0,0,0,0,0,1) << "1::1";
+ QTest::newRow("::1") << Ip6(0,0,0,0,0,0,0,1) << "::1";
+ QTest::newRow("1::") << Ip6(1,0,0,0,0,0,0,0) << "1::";
+ QTest::newRow("::") << Ip6(0,0,0,0,0,0,0,0) << "::";
+
+ QTest::newRow("::1.2.3.4") << Ip6(0,0,0,0,0,0,0x102,0x304) << "::1.2.3.4";
+ QTest::newRow("::ffff:1.2.3.4") << Ip6(0,0,0,0,0,0xffff,0x102,0x304) << "::ffff:1.2.3.4";
+}
+
+void tst_QIpAddress::ip6ToString()
+{
+ QFETCH(Ip6, ip);
+ QFETCH(QString, expected);
+
+#if defined(__GLIBC__) && defined(AF_INET6)
+ {
+ char buf[INET6_ADDRSTRLEN];
+ bool ok = inet_ntop(AF_INET6, ip.u8, buf, sizeof buf) != 0;
+ QVERIFY(ok);
+ QCOMPARE(QString(buf), expected);
+ }
+#endif
+
+ QString result;
+ QIPAddressUtils::toString(result, ip.u8);
+ QCOMPARE(result, expected);
+}
+
QTEST_APPLESS_MAIN(tst_QIpAddress)
#include "tst_qipaddress.moc"