diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 7eeb4e5a51..bff351c34f 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -134,15 +134,40 @@ QHostAddressPrivate::QHostAddressPrivate() void QHostAddressPrivate::setAddress(quint32 a_) { a = a_; + //create mapped address + memset(&a6, 0, sizeof(a6)); + 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) +{ + 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]; + return true; +} + void QHostAddressPrivate::setAddress(const quint8 *a_) { for (int i = 0; i < 16; i++) a6[i] = a_[i]; - protocol = QAbstractSocket::IPv6Protocol; + a = 0; + if (parseMappedAddress(a, a6)) + protocol = QAbstractSocket::IPv4Protocol; + else + protocol = QAbstractSocket::IPv6Protocol; isParsed = true; } @@ -150,7 +175,10 @@ void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_) { a6 = a_; a = 0; - protocol = QAbstractSocket::IPv6Protocol; + if (parseMappedAddress(a, a6)) + protocol = QAbstractSocket::IPv4Protocol; + else + protocol = QAbstractSocket::IPv6Protocol; isParsed = true; } @@ -447,8 +475,9 @@ void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol prot \value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1"). \value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1"). \value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255"). - \value Any The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). - \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). + \value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interaces. + \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interaces. + \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. @@ -548,12 +577,16 @@ QHostAddress::QHostAddress(SpecialAddress address) case LocalHostIPv6: setAddress(QLatin1String("::1")); break; - case Any: + case AnyIPv4: setAddress(QLatin1String("0.0.0.0")); break; case AnyIPv6: setAddress(QLatin1String("::")); break; + case Any: + d->clear(); + d->protocol = QAbstractSocket::AnyIPProtocol; + break; } } @@ -679,8 +712,11 @@ void QHostAddress::setAddress(const struct sockaddr *sockaddr) For example, if the address is 127.0.0.1, the returned value is 2130706433 (i.e. 0x7f000001). - This value is only valid if the Protocol() is - \l{QAbstractSocket::}{IPv4Protocol}. + 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) \sa toString() */ @@ -705,8 +741,11 @@ QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const \snippet doc/src/snippets/code/src_network_kernel_qhostaddress.cpp 0 - This value is only valid if the protocol() is + This value is valid if the protocol() is \l{QAbstractSocket::}{IPv6Protocol}. + If the protocol is + \l{QAbstractSocket::}{IPv4Protocol}, + then the address is returned an an IPv4 mapped IPv6 address. (RFC4291) \sa toString() */ @@ -722,13 +761,15 @@ Q_IPV6ADDR QHostAddress::toIPv6Address() const For example, if the address is the IPv4 address 127.0.0.1, the returned string is "127.0.0.1". For IPv6 the string format will follow the RFC5952 recommendation. + For QHostAddress::Any, its IPv4 address will be returned ("0.0.0.0") \sa toIPv4Address() */ QString QHostAddress::toString() const { QT_ENSURE_PARSED(this); - if (d->protocol == QAbstractSocket::IPv4Protocol) { + if (d->protocol == QAbstractSocket::IPv4Protocol + || d->protocol == QAbstractSocket::AnyIPProtocol) { quint32 i = toIPv4Address(); QString s; s.sprintf("%d.%d.%d.%d", (i>>24) & 0xff, (i>>16) & 0xff, @@ -1183,6 +1224,9 @@ QDataStream &operator>>(QDataStream &in, QHostAddress &address) address.setScopeId(scope); } break; + case QAbstractSocket::AnyIPProtocol: + address = QHostAddress::Any; + break; default: address.clear(); in.setStatus(QDataStream::ReadCorruptData); diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h index 486f2322ae..efb3198fc0 100644 --- a/src/network/kernel/qhostaddress.h +++ b/src/network/kernel/qhostaddress.h @@ -76,7 +76,8 @@ public: LocalHost, LocalHostIPv6, Any, - AnyIPv6 + AnyIPv6, + AnyIPv4 }; QHostAddress(); diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index 1959fabdfc..2717ceb58a 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -74,6 +74,7 @@ public: enum NetworkLayerProtocol { IPv4Protocol, IPv6Protocol, + AnyIPProtocol, UnknownNetworkLayerProtocol = -1 }; enum SocketError { diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index c5c4b325d0..a024cd42d1 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -74,6 +74,11 @@ struct qt_sockaddr_storage { char __ss_pad2[QT_SS_PAD2SIZE]; }; +#ifdef Q_OS_WIN +#define QT_SOCKLEN_T int +#define QT_SOCKOPTLEN_T int +#endif + // sockaddr_in6 size changed between old and new SDK // Only the new version is the correct one, so always // use this structure. @@ -265,6 +270,10 @@ public: int nativeSelect(int timeout, bool selectForRead) const; int nativeSelect(int timeout, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const; +#ifdef Q_OS_WIN + void setPortAndAddress(sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6, + quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize); +#endif void nativeClose(); diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 39570c8c04..26053981ce 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -163,7 +163,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc QAbstractSocket::NetworkLayerProtocol socketProtocol) { #ifndef QT_NO_IPV6 - int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET; + int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET; #else Q_UNUSED(socketProtocol); int protocol = AF_INET; @@ -495,7 +495,14 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 #if !defined(QT_NO_IPV6) struct sockaddr_in6 sockAddrIPv6; - if (address.protocol() == QAbstractSocket::IPv6Protocol) { + if (address.protocol() == QAbstractSocket::IPv6Protocol || address.protocol() == QAbstractSocket::AnyIPProtocol) { +#ifdef IPV6_V6ONLY + int ipv6only = 0; + if (address.protocol() == QAbstractSocket::IPv6Protocol) + ipv6only = 1; + //default value of this socket option varies depending on unix variant (or system configuration on BSD), so always set it explicitly + ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); +#endif memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); sockAddrIPv6.sin6_family = AF_INET6; sockAddrIPv6.sin6_port = htons(port); @@ -866,7 +873,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l #if !defined(QT_NO_IPV6) struct sockaddr_in6 sockAddrIPv6; - if (host.protocol() == QAbstractSocket::IPv6Protocol) { + if (host.protocol() == QAbstractSocket::IPv6Protocol + || socketProtocol == QAbstractSocket::IPv6Protocol) { memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6)); sockAddrIPv6.sin6_family = AF_INET6; sockAddrIPv6.sin6_port = htons(port); diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 88b87b98fe..ba62bd6da2 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -159,11 +159,6 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxLength) #define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) /* disallow local address reuse */ #endif -//### -#define QT_SOCKLEN_T int -#define QT_SOCKOPTLEN_T int - - /* Extracts the port and address from a sockaddr, and stores them in \a port and \a addr if they are non-null. @@ -202,11 +197,13 @@ static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt Sets the port and address to a sockaddr. Requires that sa point to the IPv6 struct if the address is IPv6. */ -static inline void qt_socket_setPortAndAddress(SOCKET socketDescriptor, sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6, +void QNativeSocketEnginePrivate::setPortAndAddress(sockaddr_in * sockAddrIPv4, qt_sockaddr_in6 * sockAddrIPv6, quint16 port, const QHostAddress & address, sockaddr ** sockAddrPtr, QT_SOCKLEN_T *sockAddrSize) { #if !defined(QT_NO_IPV6) - if (address.protocol() == QAbstractSocket::IPv6Protocol) { + if (address.protocol() == QAbstractSocket::IPv6Protocol + || address.protocol() == QAbstractSocket::AnyIPProtocol + || socketProtocol == QAbstractSocket::IPv6Protocol) { memset(sockAddrIPv6, 0, sizeof(qt_sockaddr_in6)); sockAddrIPv6->sin6_family = AF_INET6; sockAddrIPv6->sin6_scope_id = address.scopeId().toInt(); @@ -306,7 +303,9 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc } */ - int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET; + //Windows XP and 2003 support IPv6 but not dual stack sockets + int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol + || (socketProtocol == QAbstractSocket::AnyIPProtocol && QSysInfo::windowsVersion() >= QSysInfo::WV_6_0)) ? AF_INET6 : AF_INET; int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM; // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking // and recomends alwasy doing it for cross windows version comapablity. @@ -602,7 +601,7 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin struct sockaddr *sockAddrPtr = 0; QT_SOCKLEN_T sockAddrSize = 0; - qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); + setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); forever { int connectResult = ::WSAConnect(socketDescriptor, sockAddrPtr, sockAddrSize, 0,0,0,0); @@ -708,19 +707,35 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &a, quint16 port) { QHostAddress address = a; + DWORD ipv6only = 0; switch (address.protocol()) { case QAbstractSocket::IPv6Protocol: if (address.toIPv6Address()[0] == 0xff) { // binding to a multicast address address = QHostAddress(QHostAddress::AnyIPv6); } +#if !defined (QT_NO_IPV6) && defined (IPV6_V6ONLY) + //This is default in current windows versions, it may change in future so set it explicitly + if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) { + ipv6only = 1; + ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); + } +#endif break; case QAbstractSocket::IPv4Protocol: if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) { // binding to a multicast address - address = QHostAddress(QHostAddress::Any); + address = QHostAddress(QHostAddress::AnyIPv4); } break; + case QAbstractSocket::AnyIPProtocol: +#if !defined (QT_NO_IPV6) && defined (IPV6_V6ONLY) + if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) + ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); + else +#endif + address = QHostAddress(QHostAddress::AnyIPv4); //xp/WS2003 and earlier don't support dual stack, so bind to IPv4 + break; default: break; } @@ -730,7 +745,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &a, quint16 port) struct sockaddr *sockAddrPtr = 0; QT_SOCKLEN_T sockAddrSize = 0; - qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); + setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); int bindResult = ::bind(socketDescriptor, sockAddrPtr, sockAddrSize); @@ -1182,7 +1197,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l struct sockaddr *sockAddrPtr = 0; QT_SOCKLEN_T sockAddrSize = 0; - qt_socket_setPortAndAddress(socketDescriptor, &sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); + setPortAndAddress(&sockAddrIPv4, &sockAddrIPv6, port, address, &sockAddrPtr, &sockAddrSize); WSABUF buf; #if !defined(Q_OS_WINCE) diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index ab757987f6..514a7a0f6f 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -827,7 +827,7 @@ void QSocks5SocketEnginePrivate::sendRequestMethod() //### set error code .... return; } else if (!peerName.isEmpty() && !qt_socks5_set_host_name_and_port(peerName, port, &buf)) { - QSOCKS5_DEBUG << "error setting address" << address << " : " << port; + QSOCKS5_DEBUG << "error setting peer name" << peerName << " : " << port; //### set error code .... return; } @@ -1325,12 +1325,18 @@ void QSocks5SocketEnginePrivate::_q_udpSocketReadNotification() } #endif // QT_NO_UDPSOCKET -bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port) +bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port) { Q_D(QSocks5SocketEngine); // when bind wee will block until the bind is finished as the info from the proxy server is needed + QHostAddress address; + if (addr.protocol() == QAbstractSocket::AnyIPProtocol) + address = QHostAddress::AnyIPv4; //SOCKS5 doesnt support dual stack, and there isn't any implementation of udp on ipv6 yet + else + address = addr; + if (!d->data) { if (socketType() == QAbstractSocket::TcpSocket) { d->initialize(QSocks5SocketEnginePrivate::BindMode); diff --git a/tests/auto/qhostaddress/tst_qhostaddress.cpp b/tests/auto/qhostaddress/tst_qhostaddress.cpp index 08eb63cff8..b20e07be03 100644 --- a/tests/auto/qhostaddress/tst_qhostaddress.cpp +++ b/tests/auto/qhostaddress/tst_qhostaddress.cpp @@ -269,7 +269,10 @@ void tst_QHostAddress::specialAddresses_data() QTest::newRow("broadcast_2") << QString("255.255.255.255") << (int)QHostAddress::Broadcast << true; QTest::newRow("any_ipv6") << QString("::") << (int)QHostAddress::AnyIPv6 << true; - QTest::newRow("any_ipv4") << QString("0.0.0.0") << (int)QHostAddress::Any << true; + QTest::newRow("any_ipv4") << QString("0.0.0.0") << (int)QHostAddress::AnyIPv4 << true; + + QTest::newRow("dual_not_ipv6") << QString("::") << (int)QHostAddress::Any << false; + QTest::newRow("dual_not_ipv4") << QString("0.0.0.0") << (int)QHostAddress::Any << false; } @@ -366,8 +369,9 @@ void tst_QHostAddress::streaming_data() QTest::newRow("8") << QHostAddress(QHostAddress::LocalHostIPv6); QTest::newRow("9") << QHostAddress(QHostAddress::Broadcast); QTest::newRow("10") << QHostAddress(QHostAddress::Any); - QTest::newRow("11") << QHostAddress(QHostAddress::AnyIPv6); - QTest::newRow("12") << QHostAddress("foo.bar.com"); + QTest::newRow("11") << QHostAddress(QHostAddress::AnyIPv4); + QTest::newRow("12") << QHostAddress(QHostAddress::AnyIPv6); + QTest::newRow("13") << QHostAddress("foo.bar.com"); } void tst_QHostAddress::streaming() @@ -409,26 +413,26 @@ void tst_QHostAddress::parseSubnet_data() QTest::newRow("invalid_23") << "ffff::/ff00::" << QHostAddress() << -1; // correct IPv4 with netmask - QTest::newRow("netmask_0") << "0.0.0.0/0.0.0.0" << QHostAddress(QHostAddress::Any) << 0; - QTest::newRow("netmask_1") << "0.0.0.0/255.128.0.0" << QHostAddress(QHostAddress::Any) << 9; - QTest::newRow("netmask_2") << "0.0.0.0/255.192.0.0" << QHostAddress(QHostAddress::Any) << 10; - QTest::newRow("netmask_3") << "0.0.0.0/255.224.0.0" << QHostAddress(QHostAddress::Any) << 11; - QTest::newRow("netmask_4") << "0.0.0.0/255.240.0.0" << QHostAddress(QHostAddress::Any) << 12; - QTest::newRow("netmask_5") << "0.0.0.0/255.248.0.0" << QHostAddress(QHostAddress::Any) << 13; - QTest::newRow("netmask_6") << "0.0.0.0/255.252.0.0" << QHostAddress(QHostAddress::Any) << 14; - QTest::newRow("netmask_7") << "0.0.0.0/255.254.0.0" << QHostAddress(QHostAddress::Any) << 15; - QTest::newRow("netmask_8") << "0.0.0.0/255.255.0.0" << QHostAddress(QHostAddress::Any) << 16; - QTest::newRow("netmask_16") << "0.0.0.0/255.255.0.0" << QHostAddress(QHostAddress::Any) << 16; - QTest::newRow("netmask_24") << "0.0.0.0/255.255.255.0" << QHostAddress(QHostAddress::Any) << 24; - QTest::newRow("netmask_31") << "0.0.0.0/255.255.255.254" << QHostAddress(QHostAddress::Any) << 31; - QTest::newRow("netmask_32") << "0.0.0.0/255.255.255.255" << QHostAddress(QHostAddress::Any) << 32; + QTest::newRow("netmask_0") << "0.0.0.0/0.0.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 0; + QTest::newRow("netmask_1") << "0.0.0.0/255.128.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 9; + QTest::newRow("netmask_2") << "0.0.0.0/255.192.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 10; + QTest::newRow("netmask_3") << "0.0.0.0/255.224.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 11; + QTest::newRow("netmask_4") << "0.0.0.0/255.240.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 12; + QTest::newRow("netmask_5") << "0.0.0.0/255.248.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 13; + QTest::newRow("netmask_6") << "0.0.0.0/255.252.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 14; + QTest::newRow("netmask_7") << "0.0.0.0/255.254.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 15; + QTest::newRow("netmask_8") << "0.0.0.0/255.255.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 16; + QTest::newRow("netmask_16") << "0.0.0.0/255.255.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 16; + QTest::newRow("netmask_24") << "0.0.0.0/255.255.255.0" << QHostAddress(QHostAddress::AnyIPv4) << 24; + QTest::newRow("netmask_31") << "0.0.0.0/255.255.255.254" << QHostAddress(QHostAddress::AnyIPv4) << 31; + QTest::newRow("netmask_32") << "0.0.0.0/255.255.255.255" << QHostAddress(QHostAddress::AnyIPv4) << 32; // correct IPv4 with prefix - QTest::newRow("prefix_0") << "0.0.0.0/0" << QHostAddress(QHostAddress::Any) << 0; - QTest::newRow("prefix_1") << "0.0.0.0/1" << QHostAddress(QHostAddress::Any) << 1; - QTest::newRow("prefix_9") << "0.0.0.0/9" << QHostAddress(QHostAddress::Any) << 9; - QTest::newRow("prefix_31") << "0.0.0.0/31" << QHostAddress(QHostAddress::Any) << 31; - QTest::newRow("prefix_32") << "0.0.0.0/32" << QHostAddress(QHostAddress::Any) << 32; + QTest::newRow("prefix_0") << "0.0.0.0/0" << QHostAddress(QHostAddress::AnyIPv4) << 0; + QTest::newRow("prefix_1") << "0.0.0.0/1" << QHostAddress(QHostAddress::AnyIPv4) << 1; + QTest::newRow("prefix_9") << "0.0.0.0/9" << QHostAddress(QHostAddress::AnyIPv4) << 9; + QTest::newRow("prefix_31") << "0.0.0.0/31" << QHostAddress(QHostAddress::AnyIPv4) << 31; + QTest::newRow("prefix_32") << "0.0.0.0/32" << QHostAddress(QHostAddress::AnyIPv4) << 32; // correct IPv4 without prefix or netmask QTest::newRow("classA") << "10" << QHostAddress("10.0.0.0") << 8; @@ -533,22 +537,22 @@ void tst_QHostAddress::isInSubnet_data() // invalid QHostAddresses are never in any subnets QTest::newRow("invalid_01") << QHostAddress() << QHostAddress() << 32 << false; - QTest::newRow("invalid_02") << QHostAddress() << QHostAddress(QHostAddress::Any) << 32 << false; - QTest::newRow("invalid_03") << QHostAddress() << QHostAddress(QHostAddress::Any) << 8 << false; - QTest::newRow("invalid_04") << QHostAddress() << QHostAddress(QHostAddress::Any) << 0 << false; + QTest::newRow("invalid_02") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv4) << 32 << false; + QTest::newRow("invalid_03") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv4) << 8 << false; + QTest::newRow("invalid_04") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv4) << 0 << false; QTest::newRow("invalid_05") << QHostAddress() << QHostAddress("255.255.255.0") << 24 << false; QTest::newRow("invalid_06") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv6) << 0 << false; QTest::newRow("invalid_07") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv6) << 32 << false; QTest::newRow("invalid_08") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv6) << 128<< false; // and no host address can be in a subnet whose prefix is invalid - QTest::newRow("invalid_20") << QHostAddress(QHostAddress::Any) << QHostAddress() << 16 << false; + QTest::newRow("invalid_20") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress() << 16 << false; QTest::newRow("invalid_21") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress() << 16 << false; QTest::newRow("invalid_22") << QHostAddress(QHostAddress::LocalHost) << QHostAddress() << 16 << false; QTest::newRow("invalid_23") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress() << 16 << false; // negative netmasks don't make sense: - QTest::newRow("invalid_30") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::Any) << -1 << false; + QTest::newRow("invalid_30") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::Any) << -1 << false; QTest::newRow("invalid_31") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv6) << -1 << false; // we don't support IPv4 belonging in an IPv6 netmask and vice-versa @@ -558,10 +562,10 @@ void tst_QHostAddress::isInSubnet_data() QTest::newRow("v4-in-v6mapped2") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("::ffff:255.0.0.0") << 113 << false; // IPv4 correct ones - QTest::newRow("netmask_0") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::Any) << 0 << true; + QTest::newRow("netmask_0") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv4) << 0 << true; QTest::newRow("netmask_0bis") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("255.255.0.0") << 0 << true; QTest::newRow("netmask_0ter") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("1.2.3.4") << 0 << true; - QTest::newRow("netmask_1") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::Any) << 1 << true; + QTest::newRow("netmask_1") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv4) << 1 << true; QTest::newRow("~netmask_1") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("128.0.0.0") << 1 << false; QTest::newRow("netmask_1bis") << QHostAddress("224.0.0.1") << QHostAddress("128.0.0.0") << 1 << true; QTest::newRow("~netmask_1bis") << QHostAddress("224.0.0.1") << QHostAddress("0.0.0.0") << 1 << false; diff --git a/tests/auto/qtcpserver/tst_qtcpserver.cpp b/tests/auto/qtcpserver/tst_qtcpserver.cpp index 3416a7cb23..beeb6c7655 100644 --- a/tests/auto/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/qtcpserver/tst_qtcpserver.cpp @@ -97,6 +97,8 @@ private slots: void constructing(); void clientServerLoop(); void ipv6Server(); + void dualStack_data(); + void dualStack(); void ipv6ServerMapped(); void crashTests(); void maxPendingConnections(); @@ -265,6 +267,44 @@ void tst_QTcpServer::ipv6Server() delete serverSocket; } +Q_DECLARE_METATYPE(QHostAddress); + +void tst_QTcpServer::dualStack_data() +{ + QTest::addColumn("bindAddress"); + QTest::addColumn("v4ok"); + QTest::addColumn("v6ok"); + QTest::newRow("any") << QHostAddress(QHostAddress::Any) << true << true; + QTest::newRow("anyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << true << false; + QTest::newRow("anyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << false << true; +} + +void tst_QTcpServer::dualStack() +{ +#ifdef QT_NO_IPV6 + QSKIP("test requires IPv6 support", SkipAll); +#else + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + QSKIP("test server proxy doesn't support ipv6", SkipSingle); + QFETCH(QHostAddress, bindAddress); + QFETCH(bool, v4ok); + QFETCH(bool, v6ok); + + QTcpServer server; + QVERIFY(server.listen(bindAddress)); + + QTcpSocket v4client; + v4client.connectToHost(QHostAddress::LocalHost, server.serverPort()); + + QTcpSocket v6client; + v6client.connectToHost(QHostAddress::LocalHostIPv6, server.serverPort()); + + QCOMPARE(v4client.waitForConnected(5000), v4ok); + QCOMPARE(v6client.waitForConnected(5000), v6ok); +#endif +} + //---------------------------------------------------------------------------------- void tst_QTcpServer::ipv6ServerMapped() { diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp index a2f8bac517..39a64ab0dc 100644 --- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp @@ -1506,7 +1506,7 @@ void tst_QTcpSocket::dontCloseOnTimeout() QVERIFY(server.listen()); QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(server.serverAddress() == QHostAddress::Any) && !(server.serverAddress() == QHostAddress::AnyIPv6)) + if (!(server.serverAddress() == QHostAddress::AnyIPv4) && !(server.serverAddress() == QHostAddress::AnyIPv6)) serverAddress = server.serverAddress(); QTcpSocket *socket = newSocket(); diff --git a/tests/auto/qudpsocket/tst_qudpsocket.cpp b/tests/auto/qudpsocket/tst_qudpsocket.cpp index 9ca049bccf..03e224682f 100644 --- a/tests/auto/qudpsocket/tst_qudpsocket.cpp +++ b/tests/auto/qudpsocket/tst_qudpsocket.cpp @@ -90,6 +90,7 @@ private slots: void loop(); void ipv6Loop_data(); void ipv6Loop(); + void dualStack(); void readLine(); void pendingDatagramSize(); void writeDatagram(); @@ -212,7 +213,7 @@ void tst_QUdpSocket::unconnectedServerAndClientTest() const char *message[] = {"Yo mista", "Yo", "Wassap"}; QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(serverSocket.localAddress() == QHostAddress::Any || serverSocket.localAddress() == QHostAddress::AnyIPv6)) + if (!(serverSocket.localAddress() == QHostAddress::AnyIPv4 || serverSocket.localAddress() == QHostAddress::AnyIPv6)) serverAddress = serverSocket.localAddress(); for (int i = 0; i < 3; ++i) { @@ -343,10 +344,10 @@ void tst_QUdpSocket::loop() QVERIFY2(paul.bind(), paul.errorString().toLatin1().constData()); QHostAddress peterAddress = QHostAddress::LocalHost; - if (!(peter.localAddress() == QHostAddress::Any || peter.localAddress() == QHostAddress::AnyIPv6)) + if (!(peter.localAddress() == QHostAddress::AnyIPv4 || peter.localAddress() == QHostAddress::AnyIPv6)) peterAddress = peter.localAddress(); QHostAddress pualAddress = QHostAddress::LocalHost; - if (!(paul.localAddress() == QHostAddress::Any || paul.localAddress() == QHostAddress::AnyIPv6)) + if (!(paul.localAddress() == QHostAddress::AnyIPv4 || paul.localAddress() == QHostAddress::AnyIPv6)) pualAddress = paul.localAddress(); QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(), @@ -428,6 +429,64 @@ void tst_QUdpSocket::ipv6Loop() } } +void tst_QUdpSocket::dualStack() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + QSKIP("test server SOCKS proxy doesn't support IPv6", SkipSingle); + QUdpSocket dualSock; + QByteArray dualData("dual"); + QVERIFY(dualSock.bind(QHostAddress(QHostAddress::Any), 0)); + + QUdpSocket v4Sock; + QByteArray v4Data("v4"); + QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0)); + + QUdpSocket v6Sock; + QByteArray v6Data("v6"); + QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0)); + + QHostAddress from; + quint16 port; + QByteArray buffer; + //test v4 -> dual + QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), dualSock.localPort()), v4Data.length()); + QVERIFY(dualSock.waitForReadyRead(5000)); + buffer.reserve(100); + qint64 size = dualSock.readDatagram(buffer.data(), 100, &from, &port); + QCOMPARE((int)size, v4Data.length()); + buffer.resize(size); + QCOMPARE(buffer, v4Data); + + //test v6 -> dual + QCOMPARE((int)v6Sock.writeDatagram(v6Data.constData(), v6Data.length(), QHostAddress(QHostAddress::LocalHostIPv6), dualSock.localPort()), v6Data.length()); + QVERIFY(dualSock.waitForReadyRead(5000)); + buffer.reserve(100); + size = dualSock.readDatagram(buffer.data(), 100, &from, &port); + QCOMPARE((int)size, v6Data.length()); + buffer.resize(size); + QCOMPARE(buffer, v6Data); + + //test dual -> v4 + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length()); + QVERIFY(v4Sock.waitForReadyRead(5000)); + buffer.reserve(100); + size = v4Sock.readDatagram(buffer.data(), 100, &from, &port); + QCOMPARE((int)size, dualData.length()); + buffer.resize(size); + QCOMPARE(buffer, dualData); + + //test dual -> v6 + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length()); + QVERIFY(v6Sock.waitForReadyRead(5000)); + buffer.reserve(100); + size = v6Sock.readDatagram(buffer.data(), 100, &from, &port); + QCOMPARE((int)size, dualData.length()); + buffer.resize(size); + QCOMPARE(buffer, dualData); + +} + void tst_QUdpSocket::empty_readyReadSlot() { QTestEventLoop::instance().exitLoop(); @@ -465,7 +524,7 @@ void tst_QUdpSocket::pendingDatagramSize() QVERIFY2(server.bind(), server.errorString().toLatin1().constData()); QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(server.localAddress() == QHostAddress::Any || server.localAddress() == QHostAddress::AnyIPv6)) + if (!(server.localAddress() == QHostAddress::AnyIPv4 || server.localAddress() == QHostAddress::AnyIPv6)) serverAddress = server.localAddress(); QUdpSocket client; @@ -519,7 +578,7 @@ void tst_QUdpSocket::writeDatagram() QVERIFY2(server.bind(), server.errorString().toLatin1().constData()); QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(server.localAddress() == QHostAddress::Any || server.localAddress() == QHostAddress::AnyIPv6)) + if (!(server.localAddress() == QHostAddress::AnyIPv4 || server.localAddress() == QHostAddress::AnyIPv6)) serverAddress = server.localAddress(); QUdpSocket client; @@ -592,7 +651,7 @@ void tst_QUdpSocket::performance() QVERIFY2(server.bind(), server.errorString().toLatin1().constData()); QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(server.localAddress() == QHostAddress::Any || server.localAddress() == QHostAddress::AnyIPv6)) + if (!(server.localAddress() == QHostAddress::AnyIPv4 || server.localAddress() == QHostAddress::AnyIPv6)) serverAddress = server.localAddress(); QUdpSocket client; @@ -1147,7 +1206,7 @@ void tst_QUdpSocket::setMulticastInterface() void tst_QUdpSocket::multicast_data() { - QHostAddress anyAddress = QHostAddress(QHostAddress::Any); + QHostAddress anyAddress = QHostAddress(QHostAddress::AnyIPv4); QHostAddress groupAddress = QHostAddress("239.255.118.62"); QHostAddress any6Address = QHostAddress(QHostAddress::AnyIPv6); QHostAddress group6Address = QHostAddress("FF01::114"); @@ -1173,8 +1232,12 @@ void tst_QUdpSocket::multicast() QFETCH(bool, joinResult); if (setProxy) { // UDP multicast does not work with proxies - if ((bindAddress.protocol() == QAbstractSocket::IPv4Protocol && (bindAddress.toIPv4Address() & 0xffff0000) == 0xefff0000) - || bindAddress.protocol() == QAbstractSocket::IPv6Protocol) { + if ( +#ifndef Q_OS_WIN + //windows native socket engine binds 0.0.0.0 instead of the requested multicast address + (bindAddress.protocol() == QAbstractSocket::IPv4Protocol && (bindAddress.toIPv4Address() & 0xffff0000) == 0xefff0000) || +#endif + bindAddress.protocol() == QAbstractSocket::IPv6Protocol) { // proxy cannot bind to IPv6 or multicast addresses bindResult = false; }