diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2015-03-11 20:13:16 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2015-08-22 22:26:43 +0000 |
commit | 2c64e05d497b460f95cd39ea20c4e805b2c8c402 (patch) | |
tree | 78b7535e915f84096036ff2ba9193a5390617362 /src | |
parent | f35b8c004e61dea8ee4ee15a8943ad2b0a0c97d0 (diff) |
QNativeSocketEngine Windows: bring bind() in line with Unix
The IPv4+IPv6 dual stack code that has been in Qt since 5.0 has been
giving test failures for tst_qudpsocket: some binds that shouldn't
succeed do succeed. Instead, copy the core code from the Unix version so
the two OSes will behave the same way.
The one difference in behavior between Windows and Unix is that on Unix
you can bind an IPv4 address to a multicast IP and on Windows you can't.
So I left the "correction" that was in the original code, but I'm unsure
if it is the right thing to do. Are people expecting to join the
multicast group this way?
Change-Id: Iee8cbc07c4434ce9b560ffff13caa1c3d5a7e8fd
Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 44 |
1 files changed, 19 insertions, 25 deletions
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 9dba6693c8..aecae40a44 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -775,42 +775,36 @@ 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); - } - //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) ); - } - break; - case QAbstractSocket::IPv4Protocol: + if (address.protocol() == QAbstractSocket::IPv4Protocol) { if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) { // binding to a multicast address address = QHostAddress(QHostAddress::AnyIPv4); } - break; - case QAbstractSocket::AnyIPProtocol: - if (QSysInfo::windowsVersion() >= QSysInfo::WV_6_0) { - ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); - } else { - address = QHostAddress(QHostAddress::AnyIPv4); //xp/WS2003 and earlier don't support dual stack, so bind to IPv4 - socketProtocol = QAbstractSocket::IPv4Protocol; - } - break; - default: - break; } qt_sockaddr aa; QT_SOCKLEN_T sockAddrSize = 0; setPortAndAddress(port, address, &aa, &sockAddrSize); + if (aa.a.sa_family == AF_INET6) { + // The default may change in future, so set it explicitly + int ipv6only = 0; + if (address.protocol() == QAbstractSocket::IPv6Protocol) + ipv6only = 1; + ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); + } + + int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize); + if (bindResult == SOCKET_ERROR && WSAGetLastError() == WSAEAFNOSUPPORT + && address.protocol() == QAbstractSocket::AnyIPProtocol) { + // retry with v4 + aa.a4.sin_family = AF_INET; + aa.a4.sin_port = htons(port); + aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address()); + sockAddrSize = sizeof(aa.a4); + bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize); + } if (bindResult == SOCKET_ERROR) { int err = WSAGetLastError(); WS_ERROR_DEBUG(err); |