summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hartmann <phartmann@rim.com>2011-10-23 20:04:52 +0200
committerPeter Hartmann <phartmann@blackberry.com>2013-05-07 16:42:40 +0200
commit6b2413cb386c718ad8974e55d5ab460b07c41a56 (patch)
treef1317a21bb99941a228e274cb68993b1c9504b5a
parent6c49238d189a2e984163f39851351e6fad831eee (diff)
[BB10-internal] Move support for socket binding from QUdpSocket to QAbstractSocketPrivate
(backport of 03f852cb47d508d98aa90f501e9b7f4214e8ad8b) This is a backport of a Qt5 commit, moving the bind method to QAbstractSocketPrivate to retain binary compatibility, yet still being able to use it from the HTTP layer (i.e. QHttpNetworkConnectionChannel). Task-number: QTBUG-121 Change-Id: I733efe90ea70c5774971f11d6a2054c84b467988 Signed-off-by: Peter Hartmann <phartmann@rim.com>
-rw-r--r--src/network/socket/qabstractsocket.cpp53
-rw-r--r--src/network/socket/qabstractsocket_p.h15
-rw-r--r--tests/auto/qtcpsocket/tst_qtcpsocket.cpp72
3 files changed, 140 insertions, 0 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 3db544b849..a11bf89636 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -1234,6 +1234,59 @@ void QAbstractSocketPrivate::resumeSocketNotifiers(QAbstractSocket *socket)
socketEngine->setExceptionNotificationEnabled(socket->d_func()->prePauseExceptionSocketNotifierState);
}
+bool QAbstractSocketPrivate::bind(QAbstractSocket *socket, const QHostAddress &address,
+ quint16 port, BindMode mode)
+{
+ QAbstractSocketPrivate *d = socket->d_func();
+
+ // now check if the socket engine is initialized and to the right type
+ if (!d->socketEngine || !d->socketEngine->isValid()) {
+ QHostAddress nullAddress;
+ d->resolveProxy(nullAddress.toString(), port);
+
+ QAbstractSocket::NetworkLayerProtocol protocol = address.protocol();
+ if (protocol == QAbstractSocket::UnknownNetworkLayerProtocol)
+ protocol = nullAddress.protocol();
+
+ if (!d->initSocketLayer(protocol))
+ return false;
+ }
+
+#ifdef Q_OS_UNIX
+ if ((mode & ShareAddress) || (mode & ReuseAddressHint))
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
+ else
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
+#endif
+#ifdef Q_OS_WIN
+ if (mode & ReuseAddressHint)
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
+ else
+ d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
+ if (mode & DontShareAddress)
+ d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 1);
+ else
+ d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 0);
+#endif
+ bool result = d->socketEngine->bind(address, port);
+ d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
+
+ if (!result) {
+ d->socketError = d->socketEngine->error();
+ socket->setErrorString(d->socketEngine->errorString());
+ emit socket->error(d->socketError);
+ return false;
+ }
+
+ d->state = QAbstractSocket::BoundState;
+ d->localAddress = d->socketEngine->localAddress();
+ d->localPort = d->socketEngine->localPort();
+
+ emit socket->stateChanged(d->state);
+ d->socketEngine->setReadNotificationEnabled(true);
+ return true;
+}
+
QAbstractSocketEngine* QAbstractSocketPrivate::getSocketEngine(QAbstractSocket *socket)
{
return socket->d_func()->socketEngine;
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index 904ee28563..9c63c1276b 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -161,9 +161,24 @@ public:
bool prePauseExceptionSocketNotifierState;
static void pauseSocketNotifiers(QAbstractSocket*);
static void resumeSocketNotifiers(QAbstractSocket*);
+
+ enum BindFlag {
+ DefaultForPlatform = 0x0,
+ ShareAddress = 0x1,
+ DontShareAddress = 0x2,
+ ReuseAddressHint = 0x4
+ };
+ Q_DECLARE_FLAGS(BindMode, BindFlag)
+
+ Q_AUTOTEST_EXPORT static bool bind(QAbstractSocket *socket, const QHostAddress &address,
+ quint16 port = 0, BindMode mode = DefaultForPlatform);
+ // we don't need the other overload for now
+
static QAbstractSocketEngine* getSocketEngine(QAbstractSocket*);
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractSocketPrivate::BindMode)
+
QT_END_NAMESPACE
#endif // QABSTRACTSOCKET_P_H
diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp
index f0efc9f832..6de324ab83 100644
--- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp
+++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp
@@ -92,6 +92,10 @@
#include <unistd.h>
#endif
+#ifdef QT_BUILD_INTERNAL
+#include "private/qabstractsocket_p.h"
+#endif
+
#include "private/qhostinfo_p.h"
#include "../network-settings.h"
@@ -141,6 +145,10 @@ public slots:
private slots:
void socketsConstructedBeforeEventLoop();
void constructing();
+#ifdef QT_BUILD_INTERNAL
+ void bind_data();
+ void bind();
+#endif
void setInvalidSocketDescriptor();
void setSocketDescriptor();
void socketDescriptor();
@@ -476,6 +484,70 @@ void tst_QTcpSocket::constructing()
//----------------------------------------------------------------------------------
+#ifdef QT_BUILD_INTERNAL
+void tst_QTcpSocket::bind_data()
+{
+ QTest::addColumn<QString>("stringAddr");
+ QTest::addColumn<bool>("successExpected");
+ QTest::addColumn<QString>("stringExpectedLocalAddress");
+
+ // iterate all interfaces, add all addresses on them as test data
+ QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
+ foreach (const QNetworkInterface &interface, interfaces) {
+ if (!interface.isValid())
+ continue;
+
+ foreach (const QNetworkAddressEntry &entry, interface.addressEntries()) {
+ if (entry.ip().isInSubnet(QHostAddress::parseSubnet("fe80::/10"))
+ || entry.ip().isInSubnet(QHostAddress::parseSubnet("169.254/16")))
+ continue; // link-local bind will fail, at least on Linux, so skip it.
+
+ QString ip(entry.ip().toString());
+ QTest::newRow(ip.toLatin1().constData()) << ip << true << ip;
+ }
+ }
+
+ // additionally, try bind to known-bad addresses, and make sure this doesn't work
+ // these ranges are guaranteed to be reserved for 'documentation purposes',
+ // and thus, should be unused in the real world. Not that I'm assuming the
+ // world is full of competent administrators, or anything.
+ QStringList knownBad;
+ knownBad << "198.51.100.1";
+ knownBad << "2001:0DB8::1";
+ foreach (const QString &badAddress, knownBad) {
+ QTest::newRow(badAddress.toLatin1().constData()) << badAddress << false << QString();
+ }
+}
+
+void tst_QTcpSocket::bind()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ QSKIP("QTBUG-22964", SkipSingle);
+ QFETCH(QString, stringAddr);
+ QFETCH(bool, successExpected);
+ QFETCH(QString, stringExpectedLocalAddress);
+
+ QHostAddress addr(stringAddr);
+ QHostAddress expectedLocalAddress(stringExpectedLocalAddress);
+
+ QTcpSocket *socket = newSocket();
+ qDebug() << "Binding " << addr;
+
+ if (successExpected) {
+ QVERIFY2(QAbstractSocketPrivate::bind(socket, addr), qPrintable(socket->errorString()));
+ } else {
+ QVERIFY(!QAbstractSocketPrivate::bind(socket, addr));
+ }
+
+ QCOMPARE(socket->localAddress(), expectedLocalAddress);
+
+ delete socket;
+}
+#endif
+
+//----------------------------------------------------------------------------------
+
void tst_QTcpSocket::setInvalidSocketDescriptor()
{
QTcpSocket *socket = newSocket();