summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
authorMartin Petersson <martin.petersson@nokia.com>2011-07-01 13:26:47 +0200
committerQt by Nokia <qt-info@nokia.com>2011-07-04 13:04:57 +0200
commit3d5d8b6c4ff08806934a07df77f9387edc4243df (patch)
tree807be5598fb2ada919d16aa8b411b77c688afce0 /src/network
parent640c5d8a992f4ac6f9068aea9ec51a99a40dfc16 (diff)
Add Happy-Eyeballs style IPv6 connection establishing.
In the cases where a DNS lookup will give you both an IPv4 and IPv6 address, this will start two connection channels at the same time. One trying to connect using IPv4 and one on IPv6. This is done so that we can use the fastest one for the connection. To do this we have to do the hostlookup in the connection. The result is then in the cache for the individual socket so it will not need to do another lookup. Task-number: QTBUG-16458 Change-Id: I806c20168d9c5edc2831b80f82a2bd570b36d5fa Reviewed-on: http://codereview.qt.nokia.com/1003 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp178
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h16
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp31
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h2
-rw-r--r--src/network/socket/qabstractsocket.cpp20
-rw-r--r--src/network/socket/qabstractsocket.h2
-rw-r--r--src/network/socket/qabstractsocket_p.h2
-rw-r--r--src/network/ssl/qsslsocket.cpp11
-rw-r--r--src/network/ssl/qsslsocket.h4
9 files changed, 238 insertions, 28 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index d950af4ee2..a8a4fd9ae7 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -46,6 +46,7 @@
#include <private/qnetworkrequest_p.h>
#include <private/qobject_p.h>
#include <private/qauthenticator_p.h>
+#include "private/qhostinfo_p.h"
#include <qnetworkproxy.h>
#include <qauthenticator.h>
@@ -83,7 +84,8 @@ const int QHttpNetworkConnectionPrivate::defaultRePipelineLength = 2;
QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt)
: state(RunningState),
hostName(hostName), port(port), encrypt(encrypt),
- channelCount(defaultChannelCount)
+ channelCount(defaultChannelCount),
+ networkLayerState(Unknown)
#ifndef QT_NO_NETWORKPROXY
, networkProxy(QNetworkProxy::NoProxy)
#endif
@@ -94,7 +96,8 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host
QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt)
: state(RunningState),
hostName(hostName), port(port), encrypt(encrypt),
- channelCount(channelCount)
+ channelCount(channelCount),
+ networkLayerState(Unknown)
#ifndef QT_NO_NETWORKPROXY
, networkProxy(QNetworkProxy::NoProxy)
#endif
@@ -174,6 +177,45 @@ int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
return 0;
}
+// If the connection is in the InProgress state channel errors should not always be
+// emitted. This function will check the status of the connection channels if we
+// have not decided the networkLayerState and will return true if the channel error
+// should be emitted by the channel.
+bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *socket)
+{
+ Q_Q(QHttpNetworkConnection);
+
+ bool emitError = true;
+ int i = indexOf(socket);
+ int otherSocket = (i == 0 ? 1 : 0);
+
+ if (networkLayerState == QHttpNetworkConnectionPrivate::InProgress) {
+ if (channels[otherSocket].isSocketBusy() && (channels[otherSocket].state != QHttpNetworkConnectionChannel::ClosingState)) {
+ // this was the first socket to fail.
+ channels[i].close();
+ emitError = false;
+ }
+ else {
+ // Both connection attempts has failed.
+ networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
+ channels[i].close();
+ emitError = true;
+ }
+ } else {
+ if ((networkLayerState == QHttpNetworkConnectionPrivate::IPv4) && (channels[i].networkLayerPreference != QAbstractSocket::IPv4Protocol)
+ || (networkLayerState == QHttpNetworkConnectionPrivate::IPv6) && (channels[i].networkLayerPreference != QAbstractSocket::IPv6Protocol)) {
+ // First connection worked so this is the second one to complete and it failed.
+ channels[i].close();
+ QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
+ emitError = false;
+ }
+ if (networkLayerState == QHttpNetworkConnectionPrivate::Unknown)
+ qWarning() << "We got a connection error when networkLayerState is Unknown";
+ }
+ return emitError;
+}
+
+
qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailable(const QHttpNetworkReply &reply) const
{
return reply.d_func()->responseData.byteAmount();
@@ -469,17 +511,23 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor
break;
}
- // this used to be called via invokeMethod and a QueuedConnection
- // It is the only place _q_startNextRequest is called directly without going
- // through the event loop using a QueuedConnection.
- // This is dangerous because of recursion that might occur when emitting
- // signals as DirectConnection from this code path. Therefore all signal
- // emissions that can come out from this code path need to
- // be QueuedConnection.
- // We are currently trying to fine-tune this.
- _q_startNextRequest();
-
-
+ // For Happy Eyeballs the networkLayerState is set to Unkown
+ // untill we have started the first connection attempt. So no
+ // request will be started untill we know if IPv4 or IPv6
+ // should be used.
+ if (networkLayerState == Unknown) {
+ startHostInfoLookup();
+ } else if ( networkLayerState == IPv4 || networkLayerState == IPv6 ) {
+ // this used to be called via invokeMethod and a QueuedConnection
+ // It is the only place _q_startNextRequest is called directly without going
+ // through the event loop using a QueuedConnection.
+ // This is dangerous because of recursion that might occur when emitting
+ // signals as DirectConnection from this code path. Therefore all signal
+ // emissions that can come out from this code path need to
+ // be QueuedConnection.
+ // We are currently trying to fine-tune this.
+ _q_startNextRequest();
+ }
return reply;
}
@@ -781,6 +829,10 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
// although it is called _q_startNextRequest, it will actually start multiple requests when possible
void QHttpNetworkConnectionPrivate::_q_startNextRequest()
{
+ // If there is no network layer state decided we should not start any new requests.
+ if (networkLayerState == Unknown || networkLayerState == InProgress)
+ return;
+
// If the QHttpNetworkConnection is currently paused then bail out immediately
if (state == PausedState)
return;
@@ -830,11 +882,15 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// connected or not. This is to reuse connected channels before we connect new once.
int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count();
for (int i = 0; i < channelCount; ++i) {
- if (channels[i].socket->state() == QAbstractSocket::ConnectingState)
+ if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) || (channels[i].socket->state() == QAbstractSocket::HostLookupState))
queuedRequest--;
if ( queuedRequest <=0 )
break;
if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
+ if (networkLayerState == IPv4)
+ channels[i].networkLayerPreference = QAbstractSocket::IPv4Protocol;
+ else if (networkLayerState == IPv6)
+ channels[i].networkLayerPreference = QAbstractSocket::IPv6Protocol;
channels[i].ensureConnection();
queuedRequest--;
}
@@ -853,6 +909,100 @@ void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply)
}
}
+
+
+// The first time we start the connection is used we do not know if we
+// should use IPv4 or IPv6. So we start a hostlookup to figure this out.
+// Later when we do the connection the socket will not need to do another
+// lookup as then the hostinfo will already be in the cache.
+void QHttpNetworkConnectionPrivate::startHostInfoLookup()
+{
+ // At this time all channels should be unconnected.
+ Q_ASSERT(!channels[0].isSocketBusy());
+ Q_ASSERT(!channels[1].isSocketBusy());
+
+ networkLayerState = InProgress;
+
+ // check if we already now can descide if this is IPv4 or IPv6
+ QHostAddress temp;
+ if (temp.setAddress(hostName)) {
+ if (temp.protocol() == QAbstractSocket::IPv4Protocol) {
+ networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
+ QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
+ return;
+ } else if (temp.protocol() == QAbstractSocket::IPv6Protocol) {
+ networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
+ QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
+ return;
+ }
+ } else {
+ int hostLookupId;
+ bool immediateResultValid = false;
+ QHostInfo hostInfo = qt_qhostinfo_lookup(hostName,
+ this->q_func(),
+ SLOT(_q_hostLookupFinished(QHostInfo)),
+ &immediateResultValid,
+ &hostLookupId);
+ if (immediateResultValid) {
+ _q_hostLookupFinished(hostInfo);
+ }
+ }
+}
+
+
+void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(QHostInfo info)
+{
+ bool bIpv4 = false;
+ bool bIpv6 = false;
+
+ foreach (QHostAddress address, info.addresses()) {
+ if (address.protocol() == QAbstractSocket::IPv4Protocol)
+ bIpv4 = true;
+ else if (address.protocol() == QAbstractSocket::IPv6Protocol)
+ bIpv6 = true;
+ }
+
+ if (bIpv4 && bIpv6)
+ startNetworkLayerStateLookup();
+ else if (bIpv4) {
+ networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
+ QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
+ } else if (bIpv6) {
+ networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
+ QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
+ } else {
+ if (dequeueRequest(channels[0].socket)) {
+ emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError);
+ networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
+ } else {
+ // Should not happen
+ qWarning() << "QHttpNetworkConnectionPrivate::_q_hostLookupFinished could not dequeu request";
+ networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
+ }
+ }
+}
+
+
+// This will be used if the host lookup found both and Ipv4 and
+// Ipv6 address. Then we will start up two connections and pick
+// the network layer of the one that finish first. The second
+// connection will then be disconnected.
+void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup()
+{
+ // At this time all channels should be unconnected.
+ Q_ASSERT(!channels[0].isSocketBusy());
+ Q_ASSERT(!channels[1].isSocketBusy());
+
+ networkLayerState = InProgress;
+
+ channels[0].networkLayerPreference = QAbstractSocket::IPv4Protocol;
+ channels[1].networkLayerPreference = QAbstractSocket::IPv6Protocol;
+
+ channels[0].ensureConnection(); // Possibly delay this one..
+ channels[1].ensureConnection();
+}
+
+
#ifndef QT_NO_BEARERMANAGEMENT
QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent, QSharedPointer<QNetworkSession> networkSession)
: QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent)
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 6c953be58d..0c86fd94b9 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -82,6 +82,7 @@ QT_BEGIN_NAMESPACE
class QHttpNetworkRequest;
class QHttpNetworkReply;
class QByteArray;
+class QHostInfo;
class QHttpNetworkConnectionPrivate;
class Q_AUTOTEST_EXPORT QHttpNetworkConnection : public QObject
@@ -132,6 +133,7 @@ private:
friend class QHttpNetworkConnectionChannel;
Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
+ Q_PRIVATE_SLOT(d_func(), void _q_hostLookupFinished(QHostInfo))
};
@@ -152,6 +154,13 @@ public:
PausedState = 1,
};
+ enum NetworkLayerPreferenceState {
+ Unknown,
+ InProgress,
+ IPv4,
+ IPv6
+ };
+
QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt);
QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt);
~QHttpNetworkConnectionPrivate();
@@ -160,6 +169,7 @@ public:
void pauseConnection();
void resumeConnection();
ConnectionState state;
+ NetworkLayerPreferenceState networkLayerState;
enum { ChunkSize = 4096 };
@@ -179,9 +189,14 @@ public:
void copyCredentials(int fromChannel, QAuthenticator *auth, bool isProxy);
+ void startHostInfoLookup();
+ void startNetworkLayerStateLookup();
+
// private slots
void _q_startNextRequest(); // send the next request from the queue
+ void _q_hostLookupFinished(QHostInfo info);
+
void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request);
QString errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket,
@@ -198,6 +213,7 @@ public:
const int channelCount;
QHttpNetworkConnectionChannel *channels; // parallel connections to the server
+ bool shouldEmitChannelError(QAbstractSocket *socket);
qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const;
qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 7c644ad4b9..b8ed8ee567 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -80,6 +80,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
#endif
, pipeliningSupported(PipeliningSupportUnknown)
, connection(0)
+ , networkLayerPreference(QAbstractSocket::AnyIPProtocol)
{
// Inlining this function in the header leads to compiler error on
// release-armv5, on at least timebox 9.2 and 10.1.
@@ -594,7 +595,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
if (ssl) {
#ifndef QT_NO_OPENSSL
QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
- sslSocket->connectToHostEncrypted(connectHost, connectPort);
+ sslSocket->connectToHostEncrypted(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
sslSocket->ignoreSslErrors(ignoreSslErrorsList);
@@ -613,12 +614,12 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
&& connection->cacheProxy().type() == QNetworkProxy::NoProxy
&& connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
#endif
- socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered);
+ socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered, networkLayerPreference);
// For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
socket->setReadBufferSize(1*1024);
#ifndef QT_NO_NETWORKPROXY
} else {
- socket->connectToHost(connectHost, connectPort);
+ socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
// limit the socket read buffer size. we will read everything into
// the QHttpNetworkReply anyway, so let's grow only that and not
@@ -1002,6 +1003,25 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
void QHttpNetworkConnectionChannel::_q_connected()
{
+ // For the Happy Eyeballs we need to check if this is the first channel to connect.
+ if (!pendingEncrypt) {
+ if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::InProgress) {
+ if (networkLayerPreference == QAbstractSocket::IPv4Protocol)
+ connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
+ else if (networkLayerPreference == QAbstractSocket::IPv6Protocol)
+ connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
+ } else {
+ if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4) && (networkLayerPreference != QAbstractSocket::IPv4Protocol))
+ || ((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv6) && (networkLayerPreference != QAbstractSocket::IPv6Protocol))) {
+ close();
+ // This is the second connection so it has to be closed and we can schedule it for another request.
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
+ }
+ //The connections networkLayerState had already been decided.
+ }
+ }
+
// improve performance since we get the request sent by the kernel ASAP
//socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
// We have this commented out now. It did not have the effect we wanted. If we want to
@@ -1089,6 +1109,11 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
QPointer<QHttpNetworkConnection> that = connection;
QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
+ // In the InProgress state the channel should not emit the error.
+ // This will instead be handled by the connection.
+ if (!connection->d_func()->shouldEmitChannelError(socket))
+ return;
+
// Need to dequeu the request so that we can emit the error.
if (!reply)
connection->d_func()->dequeueRequest(socket);
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index f635cc9557..8400f62ab9 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -136,6 +136,8 @@ public:
void detectPipeliningSupport();
QHttpNetworkConnectionChannel();
+
+ QAbstractSocket::NetworkLayerProtocol networkLayerPreference;
void setConnection(QHttpNetworkConnection *c);
QPointer<QHttpNetworkConnection> connection;
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 5316626638..9afb21155b 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -483,7 +483,8 @@ QAbstractSocketPrivate::QAbstractSocketPrivate()
hostLookupId(-1),
socketType(QAbstractSocket::UnknownSocketType),
state(QAbstractSocket::UnconnectedState),
- socketError(QAbstractSocket::UnknownSocketError)
+ socketError(QAbstractSocket::UnknownSocketError),
+ preferredNetworkLayerProtocol(QAbstractSocket::UnknownNetworkLayerProtocol)
{
}
@@ -899,7 +900,16 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo)
qWarning("QAbstractSocketPrivate::_q_startConnecting() received hostInfo for wrong lookup ID %d expected %d", hostInfo.lookupId(), hostLookupId);
}
- addresses = hostInfo.addresses();
+ // Only add the addresses for the prefered network layer.
+ // Or all if prefered network layer is not set.
+ if (preferredNetworkLayerProtocol == QAbstractSocket::UnknownNetworkLayerProtocol || preferredNetworkLayerProtocol == QAbstractSocket::AnyIPProtocol) {
+ addresses = hostInfo.addresses();
+ } else {
+ foreach (QHostAddress address, hostInfo.addresses())
+ if (address.protocol() == preferredNetworkLayerProtocol)
+ addresses += address;
+ }
+
#if defined(QABSTRACTSOCKET_DEBUG)
QString s = QLatin1String("{");
@@ -1330,8 +1340,12 @@ bool QAbstractSocket::isValid() const
\sa state(), peerName(), peerAddress(), peerPort(), waitForConnected()
*/
void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
- OpenMode openMode)
+ OpenMode openMode,
+ NetworkLayerProtocol protocol)
{
+ Q_D(QAbstractSocket);
+ d->preferredNetworkLayerProtocol = protocol;
+
QMetaObject::invokeMethod(this, "connectToHostImplementation",
Qt::DirectConnection,
Q_ARG(QString, hostName),
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
index 2717ceb58a..2501df6e3d 100644
--- a/src/network/socket/qabstractsocket.h
+++ b/src/network/socket/qabstractsocket.h
@@ -129,7 +129,7 @@ public:
virtual ~QAbstractSocket();
// ### Qt 5: Make connectToHost() and disconnectFromHost() virtual.
- void connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite);
+ void connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
void disconnectFromHost();
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index cf7d98895f..978fb1433a 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -156,6 +156,8 @@ public:
QAbstractSocket::SocketError socketError;
+ QAbstractSocket::NetworkLayerProtocol preferredNetworkLayerProtocol;
+
bool prePauseReadSocketNotifierState;
bool prePauseWriteSocketNotifierState;
bool prePauseExceptionSocketNotifierState;
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index df61fb6c18..f191ed9324 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -405,7 +405,7 @@ QSslSocket::~QSslSocket()
\sa connectToHost(), startClientEncryption(), waitForConnected(), waitForEncrypted()
*/
-void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode)
+void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode, NetworkLayerProtocol protocol)
{
Q_D(QSslSocket);
if (d->state == ConnectedState || d->state == ConnectingState) {
@@ -419,7 +419,7 @@ void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, O
// Note: When connecting to localhost, some platforms (e.g., HP-UX and some BSDs)
// establish the connection immediately (i.e., first attempt).
- connectToHost(hostName, port, mode);
+ connectToHost(hostName, port, mode, protocol);
}
/*!
@@ -434,7 +434,8 @@ void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, O
\sa connectToHostEncrypted()
*/
void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port,
- const QString &sslPeerName, OpenMode mode)
+ const QString &sslPeerName, OpenMode mode,
+ NetworkLayerProtocol protocol)
{
Q_D(QSslSocket);
if (d->state == ConnectedState || d->state == ConnectingState) {
@@ -449,7 +450,7 @@ void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port,
// Note: When connecting to localhost, some platforms (e.g., HP-UX and some BSDs)
// establish the connection immediately (i.e., first attempt).
- connectToHost(hostName, port, mode);
+ connectToHost(hostName, port, mode, protocol);
}
/*!
@@ -1740,7 +1741,7 @@ void QSslSocket::connectToHostImplementation(const QString &hostName, quint16 po
d->plainSocket->setProperty("_q_user-agent", property("_q_user-agent"));
#endif
QIODevice::open(openMode);
- d->plainSocket->connectToHost(hostName, port, openMode);
+ d->plainSocket->connectToHost(hostName, port, openMode, d->preferredNetworkLayerProtocol);
d->cachedSocketDescriptor = d->plainSocket->socketDescriptor();
}
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index 1e7c67ce91..f175ffd946 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -85,8 +85,8 @@ public:
~QSslSocket();
// Autostarting the SSL client handshake.
- void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode = ReadWrite);
- void connectToHostEncrypted(const QString &hostName, quint16 port, const QString &sslPeerName, OpenMode mode = ReadWrite);
+ void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
+ void connectToHostEncrypted(const QString &hostName, quint16 port, const QString &sslPeerName, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
bool setSocketDescriptor(int socketDescriptor, SocketState state = ConnectedState,
OpenMode openMode = ReadWrite);