From 44368b4174eedc9a2eebd9f67cf0e96f42b67188 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 6 Aug 2010 09:45:34 +0200 Subject: Fix IPv6 support on Windows We need to make sure that we use the right setsockopt level and option for the multicast TTL and loopback options. Like on UNIX, we need to use IPPROTO_IPV6 level when joining and leaving a group. Also, we cannot bind to a multicast address on Windows (but it is possible on UNIX). work around this by binding to the Any/AnyIPv6 addresses if a multicast address is passed to bind. --- src/network/socket/qnativesocketengine_win.cpp | 73 ++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 2ca1f41..f952cee 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -402,12 +402,28 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co n = SO_KEEPALIVE; break; case QNativeSocketEngine::MulticastTtlOption: - level = IPPROTO_IP; - n = IP_MULTICAST_TTL; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_HOPS; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_TTL; + } break; case QNativeSocketEngine::MulticastLoopbackOption: - level = IPPROTO_IP; - n = IP_MULTICAST_LOOP; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_LOOP; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_LOOP; + } break; } @@ -470,12 +486,28 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt n = SO_KEEPALIVE; break; case QNativeSocketEngine::MulticastTtlOption: - level = IPPROTO_IP; - n = IP_MULTICAST_TTL; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_HOPS; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_TTL; + } break; case QNativeSocketEngine::MulticastLoopbackOption: - level = IPPROTO_IP; - n = IP_MULTICAST_LOOP; +#ifndef QT_NO_IPV6 + if (socketProtocol == QAbstractSocket::IPv6Protocol) { + level = IPPROTO_IPV6; + n = IPV6_MULTICAST_LOOP; + } else +#endif + { + level = IPPROTO_IP; + n = IP_MULTICAST_LOOP; + } break; } @@ -666,8 +698,24 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin } -bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) +bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &a, quint16 port) { + QHostAddress address = a; + switch (address.protocol()) { + case QAbstractSocket::IPv6Protocol: + if (address.toIPv6Address()[0] == 0xff) { + // binding to a multicast address + address = QHostAddress(QHostAddress::AnyIPv6); + } + break; + case QAbstractSocket::IPv4Protocol: + if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) { + // binding to a multicast address + address = QHostAddress(QHostAddress::Any); + } + break; + } + struct sockaddr_in sockAddrIPv4; qt_sockaddr_in6 sockAddrIPv6; struct sockaddr *sockAddrPtr = 0; @@ -771,6 +819,7 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, const QHostAddress &groupAddress, const QNetworkInterface &iface) { + int level = 0; int sockOpt = 0; char *sockArg; int sockArgSize; @@ -780,7 +829,8 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, struct ipv6_mreq mreq6; if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) { - sockOpt = how6; + level = IPPROTO_IPV6; + sockOpt = how6; sockArg = reinterpret_cast(&mreq6); sockArgSize = sizeof(mreq6); memset(&mreq6, 0, sizeof(mreq6)); @@ -790,6 +840,7 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, } else #endif if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { + level = IPPROTO_IP; sockOpt = how4; sockArg = reinterpret_cast(&mreq4); sockArgSize = sizeof(mreq4); @@ -816,7 +867,7 @@ static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, return false; } - int res = setsockopt(d->socketDescriptor, IPPROTO_IP, sockOpt, sockArg, sockArgSize); + int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize); if (res == -1) { d->setError(QAbstractSocket::UnsupportedSocketOperationError, QNativeSocketEnginePrivate::OperationUnsupportedErrorString); -- cgit v0.12