Fix multicast join/leave when binding to QHostAddress::Any.

On OS X and Windows, this was not working, because the socket was being bound
in v6 mode (due to ::Any being for dual mode), but the address passed was a v4
address, meaning it took the wrong codepath. Linux, strangely, apparently works
anyway.

This is fixable in OS X (by using the v6 join path when bound in v6/dual mode),
but the same fix doesn't work on Windows, failing with WSAEADDRNOTAVAIL.

Don't allow this behaviour, and provide a sane error message telling the user
what to do instead.

Done-with: Shane Kearns
Task-number: QTBUG-25047
Change-Id: Iaf5bbee82e13ac92e11b60c558f5af9ce26f474b
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
This commit is contained in:
Robin Burchell 2012-03-30 16:23:24 +02:00 committed by Qt by Nokia
parent c7f8f459bd
commit c82d40749d
4 changed files with 21 additions and 1 deletions

View File

@ -52,7 +52,7 @@ Receiver::Receiver(QWidget *parent)
quitButton = new QPushButton(tr("&Quit"));
udpSocket = new QUdpSocket(this);
udpSocket->bind(45454, QUdpSocket::ShareAddress);
udpSocket->bind(QHostAddress::AnyIPv4, 45454, QUdpSocket::ShareAddress);
udpSocket->joinMulticastGroup(groupAddress);
connect(udpSocket, SIGNAL(readyRead()),

View File

@ -637,6 +637,19 @@ bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress,
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::joinMulticastGroup(), false);
Q_CHECK_STATE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false);
Q_CHECK_TYPE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false);
// if the user binds a socket to an IPv6 address (or QHostAddress::Any) and
// then attempts to join an IPv4 multicast group, this won't work on
// Windows. In order to make this cross-platform, we warn & fail on all
// platforms.
if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol &&
(d->socketProtocol == QAbstractSocket::IPv6Protocol ||
d->socketProtocol == QAbstractSocket::AnyIPProtocol)) {
qWarning("QAbstractSocket: cannot bind to QHostAddress::Any (or an IPv6 address) and join an IPv4 multicast group");
qWarning("QAbstractSocket: bind to QHostAddress::AnyIPv4 instead if you want to do this");
return false;
}
return d->nativeJoinMulticastGroup(groupAddress, iface);
}

View File

@ -178,6 +178,10 @@ QUdpSocket::~QUdpSocket()
interface chosen by the operating system. The socket must be in BoundState,
otherwise an error occurs.
Note that if you are attempting to join an IPv4 group, your socket must not
be bound using IPv6 (or in dual mode, using QHostAddress::Any). You must use
QHostAddress::AnyIPv4 instead.
This function returns true if successful; otherwise it returns false
and sets the socket error accordingly.

View File

@ -1202,6 +1202,7 @@ void tst_QUdpSocket::multicast_data()
QHostAddress groupAddress = QHostAddress("239.255.118.62");
QHostAddress any6Address = QHostAddress(QHostAddress::AnyIPv6);
QHostAddress group6Address = QHostAddress("FF01::114");
QHostAddress dualAddress = QHostAddress(QHostAddress::Any);
QTest::addColumn<QHostAddress>("bindAddress");
QTest::addColumn<bool>("bindResult");
@ -1213,6 +1214,8 @@ void tst_QUdpSocket::multicast_data()
QTest::newRow("valid bind, group ipv6 address") << any6Address << true << group6Address << true;
QTest::newRow("valid bind, invalid group ipv6 address") << any6Address << true << any6Address << false;
QTest::newRow("same bind, group ipv6 address") << group6Address << true << group6Address << true;
QTest::newRow("dual bind, group ipv4 address") << dualAddress << true << groupAddress << false;
QTest::newRow("dual bind, group ipv6 address") << dualAddress << true << group6Address << true;
}
void tst_QUdpSocket::multicast()