Skip to content

Commit 6b2413c

Browse files
Peter Hartmannphartmann
authored andcommitted
[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 <[email protected]>
1 parent 6c49238 commit 6b2413c

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

src/network/socket/qabstractsocket.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,59 @@ void QAbstractSocketPrivate::resumeSocketNotifiers(QAbstractSocket *socket)
12341234
socketEngine->setExceptionNotificationEnabled(socket->d_func()->prePauseExceptionSocketNotifierState);
12351235
}
12361236

1237+
bool QAbstractSocketPrivate::bind(QAbstractSocket *socket, const QHostAddress &address,
1238+
quint16 port, BindMode mode)
1239+
{
1240+
QAbstractSocketPrivate *d = socket->d_func();
1241+
1242+
// now check if the socket engine is initialized and to the right type
1243+
if (!d->socketEngine || !d->socketEngine->isValid()) {
1244+
QHostAddress nullAddress;
1245+
d->resolveProxy(nullAddress.toString(), port);
1246+
1247+
QAbstractSocket::NetworkLayerProtocol protocol = address.protocol();
1248+
if (protocol == QAbstractSocket::UnknownNetworkLayerProtocol)
1249+
protocol = nullAddress.protocol();
1250+
1251+
if (!d->initSocketLayer(protocol))
1252+
return false;
1253+
}
1254+
1255+
#ifdef Q_OS_UNIX
1256+
if ((mode & ShareAddress) || (mode & ReuseAddressHint))
1257+
d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
1258+
else
1259+
d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
1260+
#endif
1261+
#ifdef Q_OS_WIN
1262+
if (mode & ReuseAddressHint)
1263+
d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
1264+
else
1265+
d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
1266+
if (mode & DontShareAddress)
1267+
d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 1);
1268+
else
1269+
d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 0);
1270+
#endif
1271+
bool result = d->socketEngine->bind(address, port);
1272+
d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
1273+
1274+
if (!result) {
1275+
d->socketError = d->socketEngine->error();
1276+
socket->setErrorString(d->socketEngine->errorString());
1277+
emit socket->error(d->socketError);
1278+
return false;
1279+
}
1280+
1281+
d->state = QAbstractSocket::BoundState;
1282+
d->localAddress = d->socketEngine->localAddress();
1283+
d->localPort = d->socketEngine->localPort();
1284+
1285+
emit socket->stateChanged(d->state);
1286+
d->socketEngine->setReadNotificationEnabled(true);
1287+
return true;
1288+
}
1289+
12371290
QAbstractSocketEngine* QAbstractSocketPrivate::getSocketEngine(QAbstractSocket *socket)
12381291
{
12391292
return socket->d_func()->socketEngine;

src/network/socket/qabstractsocket_p.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,24 @@ class QAbstractSocketPrivate : public QIODevicePrivate, public QAbstractSocketEn
161161
bool prePauseExceptionSocketNotifierState;
162162
static void pauseSocketNotifiers(QAbstractSocket*);
163163
static void resumeSocketNotifiers(QAbstractSocket*);
164+
165+
enum BindFlag {
166+
DefaultForPlatform = 0x0,
167+
ShareAddress = 0x1,
168+
DontShareAddress = 0x2,
169+
ReuseAddressHint = 0x4
170+
};
171+
Q_DECLARE_FLAGS(BindMode, BindFlag)
172+
173+
Q_AUTOTEST_EXPORT static bool bind(QAbstractSocket *socket, const QHostAddress &address,
174+
quint16 port = 0, BindMode mode = DefaultForPlatform);
175+
// we don't need the other overload for now
176+
164177
static QAbstractSocketEngine* getSocketEngine(QAbstractSocket*);
165178
};
166179

180+
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractSocketPrivate::BindMode)
181+
167182
QT_END_NAMESPACE
168183

169184
#endif // QABSTRACTSOCKET_P_H

tests/auto/qtcpsocket/tst_qtcpsocket.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@
9292
#include <unistd.h>
9393
#endif
9494

95+
#ifdef QT_BUILD_INTERNAL
96+
#include "private/qabstractsocket_p.h"
97+
#endif
98+
9599
#include "private/qhostinfo_p.h"
96100

97101
#include "../network-settings.h"
@@ -141,6 +145,10 @@ public slots:
141145
private slots:
142146
void socketsConstructedBeforeEventLoop();
143147
void constructing();
148+
#ifdef QT_BUILD_INTERNAL
149+
void bind_data();
150+
void bind();
151+
#endif
144152
void setInvalidSocketDescriptor();
145153
void setSocketDescriptor();
146154
void socketDescriptor();
@@ -476,6 +484,70 @@ void tst_QTcpSocket::constructing()
476484

477485
//----------------------------------------------------------------------------------
478486

487+
#ifdef QT_BUILD_INTERNAL
488+
void tst_QTcpSocket::bind_data()
489+
{
490+
QTest::addColumn<QString>("stringAddr");
491+
QTest::addColumn<bool>("successExpected");
492+
QTest::addColumn<QString>("stringExpectedLocalAddress");
493+
494+
// iterate all interfaces, add all addresses on them as test data
495+
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
496+
foreach (const QNetworkInterface &interface, interfaces) {
497+
if (!interface.isValid())
498+
continue;
499+
500+
foreach (const QNetworkAddressEntry &entry, interface.addressEntries()) {
501+
if (entry.ip().isInSubnet(QHostAddress::parseSubnet("fe80::/10"))
502+
|| entry.ip().isInSubnet(QHostAddress::parseSubnet("169.254/16")))
503+
continue; // link-local bind will fail, at least on Linux, so skip it.
504+
505+
QString ip(entry.ip().toString());
506+
QTest::newRow(ip.toLatin1().constData()) << ip << true << ip;
507+
}
508+
}
509+
510+
// additionally, try bind to known-bad addresses, and make sure this doesn't work
511+
// these ranges are guaranteed to be reserved for 'documentation purposes',
512+
// and thus, should be unused in the real world. Not that I'm assuming the
513+
// world is full of competent administrators, or anything.
514+
QStringList knownBad;
515+
knownBad << "198.51.100.1";
516+
knownBad << "2001:0DB8::1";
517+
foreach (const QString &badAddress, knownBad) {
518+
QTest::newRow(badAddress.toLatin1().constData()) << badAddress << false << QString();
519+
}
520+
}
521+
522+
void tst_QTcpSocket::bind()
523+
{
524+
QFETCH_GLOBAL(bool, setProxy);
525+
if (setProxy)
526+
QSKIP("QTBUG-22964", SkipSingle);
527+
QFETCH(QString, stringAddr);
528+
QFETCH(bool, successExpected);
529+
QFETCH(QString, stringExpectedLocalAddress);
530+
531+
QHostAddress addr(stringAddr);
532+
QHostAddress expectedLocalAddress(stringExpectedLocalAddress);
533+
534+
QTcpSocket *socket = newSocket();
535+
qDebug() << "Binding " << addr;
536+
537+
if (successExpected) {
538+
QVERIFY2(QAbstractSocketPrivate::bind(socket, addr), qPrintable(socket->errorString()));
539+
} else {
540+
QVERIFY(!QAbstractSocketPrivate::bind(socket, addr));
541+
}
542+
543+
QCOMPARE(socket->localAddress(), expectedLocalAddress);
544+
545+
delete socket;
546+
}
547+
#endif
548+
549+
//----------------------------------------------------------------------------------
550+
479551
void tst_QTcpSocket::setInvalidSocketDescriptor()
480552
{
481553
QTcpSocket *socket = newSocket();

0 commit comments

Comments
 (0)