summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2015-03-11 20:13:16 -0700
committerThiago Macieira <thiago.macieira@intel.com>2015-08-22 22:26:43 +0000
commit2c64e05d497b460f95cd39ea20c4e805b2c8c402 (patch)
tree78b7535e915f84096036ff2ba9193a5390617362 /src
parentf35b8c004e61dea8ee4ee15a8943ad2b0a0c97d0 (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.cpp44
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);