IPv4 + IPv6 dual stack sockets
Adds support for binding "dual stack" sockets (via QUdpSocket or QTcpServer). A dual stack socket will accept incoming connections on either IPv4 or IPv6 interfaces. QHostAddress::Any - use this to bind a dual stack socket QHostAddress::AnyIPv6 - use this to bind a socket for IPv6 only QHostAddress::AnyIPv4 - use this to bind a socket for IPv4 only Binding to a specific address rather than one of the "any" addresses is restricting you to a protocol anyway so no behaviour change there. IPv6 sockets were previously dual stack on some OS and v6 only on others Any previously meant IPv4 only This commit implemented & tested on Windows 7, Linux (Ubuntu 10.04) and Mac OS 10.6.7. Windows XP and server 2003 do not support dual stack sockets, even though they can support IPv6. On those versions, QHostAddress::Any will still bind to IPv4 0.0.0.0 (which is also the behaviour anywhere QT_NO_IPV6 is defined) Autotests run: qudpsocket (includes a new test case) qtcpserver (includes a new test case) qtcpsocket qnetworkreply qhostaddress Task-number: QTBUG-17080 Change-Id: Id486677c4f832e18dc0ff1a86c5f5fc422c9eb4f Reviewed-on: http://codereview.qt.nokia.com/421 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Thiago Macieira <thiago.macieira@nokia.com> Reviewed-by: Markus Goetzbb10
parent
665d8a0454
commit
85136496bc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ public:
|
|||
LocalHost,
|
||||
LocalHostIPv6,
|
||||
Any,
|
||||
AnyIPv6
|
||||
AnyIPv6,
|
||||
AnyIPv4
|
||||
};
|
||||
|
||||
QHostAddress();
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ public:
|
|||
enum NetworkLayerProtocol {
|
||||
IPv4Protocol,
|
||||
IPv6Protocol,
|
||||
AnyIPProtocol,
|
||||
UnknownNetworkLayerProtocol = -1
|
||||
};
|
||||
enum SocketError {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<QHostAddress>("bindAddress");
|
||||
QTest::addColumn<bool>("v4ok");
|
||||
QTest::addColumn<bool>("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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue