Fix QTcpServer::listen() returning true when the port is in use on OS X.

Way back in the mists of time, someone added SO_REUSEPORT to socket binding,
which was great, because otherwise it meant that multiple UDP sockets couldn't
share the same port on OS X (as platforms with SO_REUSEPORT apparently don't
support rebinding with SO_REUSEADDR).

However: SO_REUSEPORT also means that *any* bind on a port will succeed, which
is most definitely not wanted in the case of TCP sockets, so check the socket
type before performing the actual bind.

Also test that multiple listens don't take effect.

Change-Id: I2f8d450bcfb8a7f3abd8918a4e789a850281dd13
Done-with: Thiago Macieira
Done-with: Shane Kearns
Task-number: QTBUG-6305
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
This commit is contained in:
Robin Burchell 2012-03-30 21:21:40 +02:00 committed by Qt by Nokia
parent 97282527ae
commit a84b42e619
2 changed files with 29 additions and 1 deletions

View File

@ -321,7 +321,13 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
}
case QNativeSocketEngine::AddressReusable:
#if defined(SO_REUSEPORT)
n = SO_REUSEPORT;
// on OS X, SO_REUSEADDR isn't sufficient to allow multiple binds to the
// same port (which is useful for multicast UDP). SO_REUSEPORT is, but
// we most definitely do not want to use this for TCP. See QTBUG-6305.
if (socketType == QAbstractSocket::UdpSocket)
n = SO_REUSEPORT;
else
n = SO_REUSEADDR;
#else
n = SO_REUSEADDR;
#endif

View File

@ -115,6 +115,10 @@ private slots:
void serverAddress_data();
void serverAddress();
void qtbug6305_data() { serverAddress_data(); }
void qtbug6305();
private:
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkSession *networkSession;
@ -828,10 +832,28 @@ void tst_QTcpServer::serverAddress()
QFETCH(QHostAddress, listenAddress);
QFETCH(QHostAddress, serverAddress);
QTcpServer server;
// TODO: why does this QSKIP?
if (!server.listen(listenAddress))
QSKIP(qPrintable(server.errorString()));
QCOMPARE(server.serverAddress(), serverAddress);
}
// on OS X, calling listen() multiple times would succeed each time, which is
// most definitely not wanted.
void tst_QTcpServer::qtbug6305()
{
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
QFETCH(QHostAddress, listenAddress);
QTcpServer server;
QVERIFY2(server.listen(listenAddress), qPrintable(server.errorString()));
QTcpServer server2;
QVERIFY(!server2.listen(listenAddress, server.serverPort())); // second listen should fail
}
QTEST_MAIN(tst_QTcpServer)
#include "tst_qtcpserver.moc"