summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2014-12-23 13:37:01 -0200
committerThiago Macieira <thiago.macieira@intel.com>2015-03-04 23:58:03 +0000
commit9fb68a90af79df3b8dc3225a3a97e2c6387afeec (patch)
treeb51f4ca6effbcf2da792595837a92198a2181f01 /src/network
parent29051bce39d24a6e33155feeec2833b79b55ff16 (diff)
Fix bind+connect in both TCP and UDP
This has been known to be broken for a while. Now it works: you can bind and you'll retain the port (and the file descriptor) for the connect call. Incidentally, in fixing the binding for more than one IP for the hostname (with event loop), this commit fixes the setSocketDescriptor XFAIL. [ChangeLog][QtNetwork] Fixed a bug that caused both QTcpSocket and QUdpSocket to close the socket and lose any bound ports before connecting. Now bind()/setSocketDescriptor() followed by connect() will retain the original file descriptor. Task-number: QTBUG-26538 Change-Id: I691caed7e8fd16a9cf687b5995afbf3006bf453a Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src/network')
-rw-r--r--src/network/kernel/qhostinfo.cpp11
-rw-r--r--src/network/kernel/qhostinfo_p.h1
-rw-r--r--src/network/socket/qabstractsocket.cpp67
-rw-r--r--src/network/socket/qabstractsocket.h2
-rw-r--r--src/network/socket/qabstractsocket_p.h2
-rw-r--r--src/network/socket/qnativesocketengine.cpp10
-rw-r--r--src/network/ssl/qsslsocket.cpp23
-rw-r--r--src/network/ssl/qsslsocket_p.h1
8 files changed, 84 insertions, 33 deletions
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index d2dc7c4850..a2ac9065fd 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -689,6 +689,7 @@ void qt_qhostinfo_clear_cache()
}
}
+#ifdef QT_BUILD_INTERNAL
void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
{
QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
@@ -697,6 +698,16 @@ void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e)
}
}
+void qt_qhostinfo_cache_inject(const QString &hostname, const QHostInfo &resolution)
+{
+ QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager();
+ if (!manager || !manager->cache.isEnabled())
+ return;
+
+ manager->cache.put(hostname, resolution);
+}
+#endif
+
// cache for 60 seconds
// cache 128 items
QHostInfoCache::QHostInfoCache() : max_age(60), enabled(true), cache(128)
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index 74cfe2a9aa..a99c3dc8ca 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -117,6 +117,7 @@ public:
QHostInfo Q_NETWORK_EXPORT qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id);
void Q_AUTOTEST_EXPORT qt_qhostinfo_clear_cache();
void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e);
+void Q_AUTOTEST_EXPORT qt_qhostinfo_cache_inject(const QString &hostname, const QHostInfo &resolution);
class QHostInfoCache
{
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index f9fe40955a..3b10387b37 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -976,7 +976,7 @@ void QAbstractSocketPrivate::startConnectingByName(const QString &host)
connectTimeElapsed = 0;
- if (initSocketLayer(QAbstractSocket::UnknownNetworkLayerProtocol)) {
+ if (cachedSocketDescriptor != -1 || initSocketLayer(QAbstractSocket::UnknownNetworkLayerProtocol)) {
if (socketEngine->connectToHostByName(host, port) ||
socketEngine->state() == QAbstractSocket::ConnectingState) {
cachedSocketDescriptor = socketEngine->socketDescriptor();
@@ -1117,7 +1117,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
host.toString().toLatin1().constData(), port, addresses.count());
#endif
- if (!initSocketLayer(host.protocol())) {
+ if (cachedSocketDescriptor == -1 && !initSocketLayer(host.protocol())) {
// hope that the next address is better
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::_q_connectToNextAddress(), failed to initialize sock layer");
@@ -1134,9 +1134,6 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
return;
}
- // cache the socket descriptor even if we're not fully connected yet
- cachedSocketDescriptor = socketEngine->socketDescriptor();
-
// Check that we're in delayed connection state. If not, try
// the next address
if (socketEngine->state() != QAbstractSocket::ConnectingState) {
@@ -1481,54 +1478,60 @@ void QAbstractSocket::setPauseMode(PauseModes pauseMode)
bool QAbstractSocket::bind(const QHostAddress &address, quint16 port, BindMode mode)
{
Q_D(QAbstractSocket);
+ return d->bind(address, port, mode);
+}
+
+bool QAbstractSocketPrivate::bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode)
+{
+ Q_Q(QAbstractSocket);
// now check if the socket engine is initialized and to the right type
- if (!d->socketEngine || !d->socketEngine->isValid()) {
+ if (!socketEngine || !socketEngine->isValid()) {
QHostAddress nullAddress;
- d->resolveProxy(nullAddress.toString(), port);
+ resolveProxy(nullAddress.toString(), port);
QAbstractSocket::NetworkLayerProtocol protocol = address.protocol();
if (protocol == QAbstractSocket::UnknownNetworkLayerProtocol)
protocol = nullAddress.protocol();
- if (!d->initSocketLayer(protocol))
+ if (!initSocketLayer(protocol))
return false;
}
- if (mode != DefaultForPlatform) {
+ if (mode != QAbstractSocket::DefaultForPlatform) {
#ifdef Q_OS_UNIX
- if ((mode & ShareAddress) || (mode & ReuseAddressHint))
- d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
+ if ((mode & QAbstractSocket::ShareAddress) || (mode & QAbstractSocket::ReuseAddressHint))
+ socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
else
- d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
+ socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
#endif
#ifdef Q_OS_WIN
- if (mode & ReuseAddressHint)
- d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
+ if (mode & QAbstractSocket::ReuseAddressHint)
+ socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 1);
else
- d->socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
- if (mode & DontShareAddress)
- d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 1);
+ socketEngine->setOption(QAbstractSocketEngine::AddressReusable, 0);
+ if (mode & QAbstractSocket::DontShareAddress)
+ socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 1);
else
- d->socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 0);
+ socketEngine->setOption(QAbstractSocketEngine::BindExclusively, 0);
#endif
}
- bool result = d->socketEngine->bind(address, port);
- d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
+ bool result = socketEngine->bind(address, port);
+ cachedSocketDescriptor = socketEngine->socketDescriptor();
if (!result) {
- d->socketError = d->socketEngine->error();
- setErrorString(d->socketEngine->errorString());
- emit error(d->socketError);
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+ emit q->error(socketError);
return false;
}
- d->state = BoundState;
- d->localAddress = d->socketEngine->localAddress();
- d->localPort = d->socketEngine->localPort();
+ state = QAbstractSocket::BoundState;
+ localAddress = socketEngine->localAddress();
+ localPort = socketEngine->localPort();
- emit stateChanged(d->state);
- d->socketEngine->setReadNotificationEnabled(true);
+ emit q->stateChanged(state);
+ socketEngine->setReadNotificationEnabled(true);
return true;
}
@@ -1605,14 +1608,16 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
d->preferredNetworkLayerProtocol = protocol;
d->hostName = hostName;
d->port = port;
- d->state = UnconnectedState;
d->buffer.clear();
d->writeBuffer.clear();
d->abortCalled = false;
d->pendingClose = false;
- d->localPort = 0;
+ if (d->state != BoundState) {
+ d->state = UnconnectedState;
+ d->localPort = 0;
+ d->localAddress.clear();
+ }
d->peerPort = 0;
- d->localAddress.clear();
d->peerAddress.clear();
d->peerName = hostName;
if (d->hostLookupId != -1) {
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
index 76b1e5f538..f3d7f13f48 100644
--- a/src/network/socket/qabstractsocket.h
+++ b/src/network/socket/qabstractsocket.h
@@ -135,9 +135,11 @@ public:
PauseModes pauseMode() const;
void setPauseMode(PauseModes pauseMode);
+ // ### Qt6: make the first one virtual
bool bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform);
bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform);
+ // ### Qt6: de-virtualize connectToHost(QHostAddress) overload
virtual void connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
virtual void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
virtual void disconnectFromHost();
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index 379657f4fa..63440b6416 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -78,6 +78,8 @@ public:
}
#endif
+ virtual bool bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode);
+
bool canReadNotification();
bool canWriteNotification();
void canCloseNotification();
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index db6c7c487a..fcfef87e3c 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -136,6 +136,12 @@ QT_BEGIN_NAMESPACE
" not in "#state1" or "#state2); \
return (returnValue); \
} } while (0)
+#define Q_CHECK_STATES3(function, state1, state2, state3, returnValue) do { \
+ if (d->socketState != (state1) && d->socketState != (state2) && d->socketState != (state3)) { \
+ qWarning(""#function" was called" \
+ " not in "#state1" or "#state2); \
+ return (returnValue); \
+ } } while (0)
#define Q_CHECK_TYPE(function, type, returnValue) do { \
if (d->socketType != (type)) { \
qWarning(#function" was called by a" \
@@ -495,7 +501,7 @@ bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 por
if (!d->checkProxy(address))
return false;
- Q_CHECK_STATES(QNativeSocketEngine::connectToHost(),
+ Q_CHECK_STATES3(QNativeSocketEngine::connectToHost(), QAbstractSocket::BoundState,
QAbstractSocket::UnconnectedState, QAbstractSocket::ConnectingState, false);
d->peerAddress = address;
@@ -961,7 +967,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
QNativeSocketEnginePrivate::TimeOutErrorString);
d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
return false;
- } else if (state() == QAbstractSocket::ConnectingState) {
+ } else if (state() == QAbstractSocket::ConnectingState || (state() == QAbstractSocket::BoundState && d->socketDescriptor != -1)) {
connectToHost(d->peerAddress, d->peerPort);
}
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 508d300d42..b1076ebd68 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -2404,6 +2404,29 @@ bool QSslSocketPrivate::isPaused() const
return paused;
}
+bool QSslSocketPrivate::bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode)
+{
+ // this function is called from QAbstractSocket::bind
+ if (!initialized)
+ init();
+ initialized = false;
+
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << "QSslSocket::bind(" << address << ',' << port << ',' << mode << ')';
+#endif
+ if (!plainSocket) {
+#ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << "\tcreating internal plain socket";
+#endif
+ createPlainSocket(QIODevice::ReadWrite);
+ }
+ bool ret = plainSocket->bind(address, port, mode);
+ localPort = plainSocket->localPort();
+ localAddress = plainSocket->localAddress();
+ cachedSocketDescriptor = plainSocket->socketDescriptor();
+ return ret;
+}
+
/*!
\internal
*/
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index b110d65f9a..5f726f2371 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -172,6 +172,7 @@ public:
static void checkSettingSslContext(QSslSocket*, QSharedPointer<QSslContext>);
static QSharedPointer<QSslContext> sslContext(QSslSocket *socket);
bool isPaused() const;
+ bool bind(const QHostAddress &address, quint16, QAbstractSocket::BindMode) Q_DECL_OVERRIDE;
void _q_connectedSlot();
void _q_hostFoundSlot();
void _q_disconnectedSlot();