summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qabstractsocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket/qabstractsocket.cpp')
-rw-r--r--src/network/socket/qabstractsocket.cpp154
1 files changed, 115 insertions, 39 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index a11bf89636..5943452e9d 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -383,6 +383,7 @@
#ifndef QT_NO_OPENSSL
#include <QtNetwork/qsslsocket.h>
+#include <private/qsslsocket_p.h>
#endif
#include <private/qthread_p.h>
@@ -486,7 +487,8 @@ QAbstractSocketPrivate::QAbstractSocketPrivate()
hostLookupId(-1),
socketType(QAbstractSocket::UnknownSocketType),
state(QAbstractSocket::UnconnectedState),
- socketError(QAbstractSocket::UnknownSocketError)
+ socketError(QAbstractSocket::UnknownSocketError),
+ localBindMode(DefaultForPlatform)
{
}
@@ -855,6 +857,18 @@ void QAbstractSocketPrivate::startConnectingByName(const QString &host)
connectTimeElapsed = 0;
+ if (!checkForBind()) {
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+ state = QAbstractSocket::UnconnectedState;
+ emit q->stateChanged(state);
+ emit q->error(socketError);
+ return;
+ } else {
+ // move immediately from BoundState to ConnectingState
+ state = QAbstractSocket::ConnectingState;
+ }
+
if (initSocketLayer(QAbstractSocket::UnknownNetworkLayerProtocol)) {
if (socketEngine->connectToHostByName(host, port) ||
socketEngine->state() == QAbstractSocket::ConnectingState) {
@@ -939,6 +953,20 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo)
/*! \internal
+ Check whether we need to bind the socket before connecting.
+*/
+bool QAbstractSocketPrivate::checkForBind() // ### how about UDP???
+{
+ Q_Q(QAbstractSocket);
+ if (!localAddress.isNull()) {
+ return bind(q, QHostAddress(localAddress.toString()), localPort, localBindMode);
+ } else { // no bind() was called or scheduled via the properties
+ return true;
+ }
+}
+
+/*! \internal
+
Called by a queued or direct connection from _q_startConnecting() or
_q_testConnection(), this function takes the first address of the
pending addresses list and tries to connect to it. If the
@@ -1005,6 +1033,18 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
continue;
}
+ if (!checkForBind()) {
+ socketError = socketEngine->error();
+ q->setErrorString(socketEngine->errorString());
+ state = QAbstractSocket::UnconnectedState;
+ emit q->stateChanged(state);
+ emit q->error(socketError);
+ return;
+ } else {
+ // move immediately from BoundState to ConnectingState
+ state = QAbstractSocket::ConnectingState;
+ }
+
// Tries to connect to the address. If it succeeds immediately
// (localhost address on BSD or any UDP connect), emit
// connected() and return.
@@ -1239,52 +1279,83 @@ bool QAbstractSocketPrivate::bind(QAbstractSocket *socket, const QHostAddress &a
{
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);
+ // If we are called before connecting, just save the state for
+ // the later bind, because upon connecting, the socket engine
+ // is reset anyhow.
+ if (d->socketType == QAbstractSocket::TcpSocket
+ && d->state == QAbstractSocket::UnconnectedState) {
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug() << "QAbstractSocketPrivate::bind() TCP socket called in unconnected state, delaying bind";
+#endif
+ socket->setLocalAddress(address); // ### Qt5: document
+ socket->setLocalPort(port);
+ d->localBindMode = mode; // we will need those 3 later when we bind again
+ return true; // actual errors will be reported when connecting
+ } else {
+ // If we are called before connecting, do the actual bind
+#if defined(QABSTRACTSOCKET_DEBUG)
+ qDebug() << "QAbstractSocketPrivate::bind() called in other state or as UDP socket, binding...";
+#endif
- QAbstractSocket::NetworkLayerProtocol protocol = address.protocol();
- if (protocol == QAbstractSocket::UnknownNetworkLayerProtocol)
- protocol = nullAddress.protocol();
+ // 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);
- if (!d->initSocketLayer(protocol))
- return false;
- }
+ 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);
+ 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 (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();
+
+ d->localAddress = d->socketEngine->localAddress();
+ d->localPort = d->socketEngine->localPort();
+
+ if (!result) {
+ d->socketError = d->socketEngine->error();
+ socket->setErrorString(d->socketEngine->errorString());
+ emit socket->error(d->socketError);
+ return false;
+ }
- if (!result) {
- d->socketError = d->socketEngine->error();
- socket->setErrorString(d->socketEngine->errorString());
- emit socket->error(d->socketError);
- return false;
+ d->state = QAbstractSocket::BoundState;
+
+ emit socket->stateChanged(d->state);
+ d->socketEngine->setReadNotificationEnabled(true);
+ return true;
}
+}
- d->state = QAbstractSocket::BoundState;
- d->localAddress = d->socketEngine->localAddress();
- d->localPort = d->socketEngine->localPort();
+void QAbstractSocketPrivate::setLocalAddress(QAbstractSocket *socket,
+ const QHostAddress &address)
+{
+ socket->setLocalAddress(address);
+}
- emit socket->stateChanged(d->state);
- d->socketEngine->setReadNotificationEnabled(true);
- return true;
+void QAbstractSocketPrivate::setLocalPort(QAbstractSocket *socket, quint16 port)
+{
+ socket->setLocalPort(port);
}
QAbstractSocketEngine* QAbstractSocketPrivate::getSocketEngine(QAbstractSocket *socket)
@@ -1416,9 +1487,9 @@ void QAbstractSocket::connectToHostImplementation(const QString &hostName, quint
d->abortCalled = false;
d->closeCalled = false;
d->pendingClose = false;
- d->localPort = 0;
+// d->localPort = 0; // preserve; this might have been set through a bind()
d->peerPort = 0;
- d->localAddress.clear();
+// d->localAddress.clear(); // preserve; this might have been set through a bind()
d->peerAddress.clear();
d->peerName = hostName;
if (d->hostLookupId != -1) {
@@ -2418,6 +2489,11 @@ void QAbstractSocket::setLocalAddress(const QHostAddress &address)
{
Q_D(QAbstractSocket);
d->localAddress = address;
+#ifndef QT_NO_OPENSSL
+ if (QSslSocket *socket = qobject_cast<QSslSocket *>(this)) {
+ QSslSocketPrivate::setLocalAddress(socket, address);
+ }
+#endif
}
/*!