From 9bc4b56656a5acabba09093e3da145bf6a4bca62 Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Fri, 16 Dec 2011 10:44:24 +0100 Subject: QNetworkAccessManager: delay IPv4 connection with Happy Eyeballs Incase we have both IPv4 and IPv6 available after the host lookup we should delay the connection attempt to IPv4. Task-number: QTBUG-23066 Change-Id: I8c0177cf125c9daae314ada73cacef790a39b856 Reviewed-by: Peter Hartmann --- src/network/access/qhttpnetworkconnection.cpp | 26 +++++++++++++++++++++- src/network/access/qhttpnetworkconnection_p.h | 4 ++++ .../access/qhttpnetworkconnectionchannel.cpp | 2 ++ 3 files changed, 31 insertions(+), 1 deletion(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index fca3d5999e..b43f2b9bcd 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -116,6 +116,7 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() void QHttpNetworkConnectionPrivate::init() { + Q_Q(QHttpNetworkConnection); for (int i = 0; i < channelCount; i++) { channels[i].setConnection(this->q_func()); channels[i].ssl = encrypt; @@ -125,6 +126,8 @@ void QHttpNetworkConnectionPrivate::init() #endif channels[i].init(); } + ipv4ConnectTimer.setSingleShot(true); + QObject::connect(&ipv4ConnectTimer, SIGNAL(timeout()), q, SLOT(_q_connectIPv4Channel())); } void QHttpNetworkConnectionPrivate::pauseConnection() @@ -185,6 +188,12 @@ bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *sock int i = indexOf(socket); int otherSocket = (i == 0 ? 1 : 0); + // If the IPv4 connection still isn't started we need to start it now. + if (ipv4ConnectTimer.isActive()) { + ipv4ConnectTimer.stop(); + channels[0].ensureConnection(); + } + if (channelCount == 1) { if (networkLayerState == QHttpNetworkConnectionPrivate::InProgress) networkLayerState = QHttpNetworkConnectionPrivate::Unknown; @@ -1010,7 +1019,18 @@ void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup() channels[0].networkLayerPreference = QAbstractSocket::IPv4Protocol; channels[1].networkLayerPreference = QAbstractSocket::IPv6Protocol; - channels[0].ensureConnection(); // Possibly delay this one.. + int timeout = 300; +#ifndef QT_NO_BEARERMANAGEMENT + if (networkSession->configuration().bearerType() == QNetworkConfiguration::Bearer2G) + timeout = 800; + else if (networkSession->configuration().bearerType() == QNetworkConfiguration::BearerCDMA2000) + timeout = 500; + else if (networkSession->configuration().bearerType() == QNetworkConfiguration::BearerWCDMA) + timeout = 500; + else if (networkSession->configuration().bearerType() == QNetworkConfiguration::BearerHSPA) + timeout = 400; +#endif + ipv4ConnectTimer.start(timeout); channels[1].ensureConnection(); } else { networkLayerState = InProgress; @@ -1019,6 +1039,10 @@ void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup() } } +void QHttpNetworkConnectionPrivate::_q_connectIPv4Channel() +{ + channels[0].ensureConnection(); +} #ifndef QT_NO_BEARERMANAGEMENT QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent, QSharedPointer networkSession) diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 70b9cf3754..18ec92a07a 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -134,6 +135,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest()) Q_PRIVATE_SLOT(d_func(), void _q_hostLookupFinished(QHostInfo)) + Q_PRIVATE_SLOT(d_func(), void _q_connectIPv4Channel()) }; @@ -196,6 +198,7 @@ public: void _q_startNextRequest(); // send the next request from the queue void _q_hostLookupFinished(QHostInfo info); + void _q_connectIPv4Channel(); void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request); @@ -209,6 +212,7 @@ public: bool encrypt; const int channelCount; + QTimer ipv4ConnectTimer; QHttpNetworkConnectionChannel *channels; // parallel connections to the server bool shouldEmitChannelError(QAbstractSocket *socket); diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 072648cf62..89873c086a 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -951,6 +951,8 @@ 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 (connection->d_func()->ipv4ConnectTimer.isActive()) + connection->d_func()->ipv4ConnectTimer.stop(); if (networkLayerPreference == QAbstractSocket::IPv4Protocol) connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4; else if (networkLayerPreference == QAbstractSocket::IPv6Protocol) -- cgit v1.2.3