diff options
author | Shane Kearns <shane.kearns@accenture.com> | 2011-01-05 11:07:56 (GMT) |
---|---|---|
committer | Shane Kearns <shane.kearns@accenture.com> | 2011-02-01 11:33:07 (GMT) |
commit | cdc4ce0acde93b23c7e4941b5c195a8d23ff6900 (patch) | |
tree | 41cfe97dbb6c881b742b41a9a1dfb5a3ac48af15 /src | |
parent | 54692812331d24939a0263a1625702670503c17a (diff) | |
download | Qt-cdc4ce0acde93b23c7e4941b5c195a8d23ff6900.zip Qt-cdc4ce0acde93b23c7e4941b5c195a8d23ff6900.tar.gz Qt-cdc4ce0acde93b23c7e4941b5c195a8d23ff6900.tar.bz2 |
Workaround crash when multiple QNetworkAccessManager instances are used
Instead of each QNetworkAccessManager owning a QNetworkSession, they now
share a QNetworkSession if they have the same QNetworkConfiguration.
QNetworkAccessManager now uses passive roaming instead of application
level roaming. The state change signal (entering connected state) is used
to indicate reconnection instead of being triggered when sending an ALR
accept().
This preserves the previous behaviour, as QNAM always accepted the
suggested access point from bearer mobility.
In the case of multithreaded applications, one QNetworkSession will be
created for each thread which uses QNetworkAccessManager, as QNetworkSession
is not thread safe.
Task-number: QT-4378
Reviewed-by: Markus Goetz
Reviewed-by: juhvu
Diffstat (limited to 'src')
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 42 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager.h | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyimpl.cpp | 6 | ||||
-rw-r--r-- | src/network/bearer/bearer.pri | 6 | ||||
-rw-r--r-- | src/network/bearer/qsharednetworksession.cpp | 90 | ||||
-rw-r--r-- | src/network/bearer/qsharednetworksession_p.h | 81 |
7 files changed, 188 insertions, 41 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index bec217b..94ce3bc 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -48,6 +48,7 @@ #include "qabstractnetworkcache.h" #include "QtNetwork/qnetworksession.h" +#include "qsharednetworksession_p.h" #include "qnetworkaccesshttpbackend_p.h" #include "qnetworkaccessftpbackend_p.h" @@ -1343,11 +1344,8 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co initializeSession = false; - if (networkSession) - delete networkSession; - if (!config.isValid()) { - networkSession = 0; + networkSession.clear(); online = false; if (networkAccessible == QNetworkAccessManager::NotAccessible) @@ -1358,18 +1356,12 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co return; } - networkSession = new QNetworkSession(config, q); + networkSession = QSharedNetworkSessionManager::getSession(config); - QObject::connect(networkSession, SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); - QObject::connect(networkSession, SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); - QObject::connect(networkSession, SIGNAL(stateChanged(QNetworkSession::State)), + QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); + QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); + QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)), q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State))); - QObject::connect(networkSession, SIGNAL(newConfigurationActivated()), - q, SLOT(_q_networkSessionNewConfigurationActivated())); - QObject::connect(networkSession, - SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool)), - q, - SLOT(_q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool))); _q_networkSessionStateChanged(networkSession->state()); } @@ -1379,32 +1371,16 @@ void QNetworkAccessManagerPrivate::_q_networkSessionClosed() if (networkSession) { networkConfiguration = networkSession->configuration().identifier(); - networkSession->deleteLater(); - networkSession = 0; - } -} - -void QNetworkAccessManagerPrivate::_q_networkSessionNewConfigurationActivated() -{ - Q_Q(QNetworkAccessManager); - - if (networkSession) { - networkSession->accept(); - - emit q->networkSessionConnected(); + networkSession.clear(); } } -void QNetworkAccessManagerPrivate::_q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &, bool) -{ - if (networkSession) - networkSession->migrate(); -} - void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state) { Q_Q(QNetworkAccessManager); + if (state == QNetworkSession::Connected) + emit q->networkSessionConnected(); if (online) { if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) { online = false; diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 95e45f0..9c551a7 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -161,8 +161,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList<QSslError>)) #if !defined(QT_NO_BEARERMANAGEMENT) && !defined(QT_MOBILITY_BEARER) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed()) - Q_PRIVATE_SLOT(d_func(), void _q_networkSessionNewConfigurationActivated()) - Q_PRIVATE_SLOT(d_func(), void _q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool)) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) #endif }; diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index 2c6ee10..cdc4b3d 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -128,7 +128,7 @@ public: #endif #ifndef QT_NO_BEARERMANAGEMENT - QNetworkSession *networkSession; + QSharedPointer<QNetworkSession> networkSession; QString networkConfiguration; QNetworkAccessManager::NetworkAccessibility networkAccessible; bool online; diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 70c318c..373cb22 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -97,7 +97,7 @@ void QNetworkReplyImplPrivate::_q_startOperation() // state changes. state = WaitingForSession; - QNetworkSession *session = manager->d_func()->networkSession; + QNetworkSession *session = manager->d_func()->networkSession.data(); if (session) { Q_Q(QNetworkReplyImpl); @@ -257,7 +257,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected() if (manager.isNull()) return; - QNetworkSession *session = manager->d_func()->networkSession; + QNetworkSession *session = manager->d_func()->networkSession.data(); if (!session) return; @@ -693,7 +693,7 @@ void QNetworkReplyImplPrivate::finished() if (!manager.isNull()) { #ifndef QT_NO_BEARERMANAGEMENT - QNetworkSession *session = manager->d_func()->networkSession; + QNetworkSession *session = manager->d_func()->networkSession.data(); if (session && session->state() == QNetworkSession::Roaming && state == Working && errorCode != QNetworkReply::OperationCanceledError) { // only content with a known size will fail with a temporary network failure error diff --git a/src/network/bearer/bearer.pri b/src/network/bearer/bearer.pri index bc5b0b5..d58d5ec 100644 --- a/src/network/bearer/bearer.pri +++ b/src/network/bearer/bearer.pri @@ -7,11 +7,13 @@ HEADERS += bearer/qnetworkconfiguration.h \ bearer/qnetworkconfiguration_p.h \ bearer/qnetworksession_p.h \ bearer/qbearerengine_p.h \ - bearer/qbearerplugin_p.h + bearer/qbearerplugin_p.h \ + bearer/qsharednetworksession_p.h SOURCES += bearer/qnetworksession.cpp \ bearer/qnetworkconfigmanager.cpp \ bearer/qnetworkconfiguration.cpp \ bearer/qnetworkconfigmanager_p.cpp \ bearer/qbearerengine.cpp \ - bearer/qbearerplugin.cpp + bearer/qbearerplugin.cpp \ + bearer/qsharednetworksession.cpp diff --git a/src/network/bearer/qsharednetworksession.cpp b/src/network/bearer/qsharednetworksession.cpp new file mode 100644 index 0000000..51b3a32 --- /dev/null +++ b/src/network/bearer/qsharednetworksession.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsharednetworksession_p.h" +#include "qbearerengine_p.h" +#include <QThreadStorage> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +QThreadStorage<QSharedNetworkSessionManager *> tls; + +inline QSharedNetworkSessionManager* sharedNetworkSessionManager() +{ + QSharedNetworkSessionManager* rv = tls.localData(); + if (!rv) { + rv = new QSharedNetworkSessionManager; + tls.setLocalData(rv); + } + return rv; +} + +QSharedPointer<QNetworkSession> QSharedNetworkSessionManager::getSession(QNetworkConfiguration config) +{ + QSharedNetworkSessionManager *m(sharedNetworkSessionManager()); + //if already have a session, return it + if (m->sessions.contains(config)) { + QSharedPointer<QNetworkSession> p = m->sessions.value(config).toStrongRef(); + if (!p.isNull()) + return p; + } + //otherwise make one + QSharedPointer<QNetworkSession> session(new QNetworkSession(config)); + m->sessions[config] = session; + return session; +} + +void QSharedNetworkSessionManager::setSession(QNetworkConfiguration config, QSharedPointer<QNetworkSession> session) +{ + QSharedNetworkSessionManager *m(sharedNetworkSessionManager()); + m->sessions[config] = session; +} + +uint qHash(const QNetworkConfiguration& config) +{ + return ((uint)config.type()) | (((uint)config.bearerType()) << 8) | (((uint)config.purpose()) << 16); +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/network/bearer/qsharednetworksession_p.h b/src/network/bearer/qsharednetworksession_p.h new file mode 100644 index 0000000..dc84166 --- /dev/null +++ b/src/network/bearer/qsharednetworksession_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSHAREDNETWORKSESSIONPRIVATE_H +#define QSHAREDNETWORKSESSIONPRIVATE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qnetworksession.h" +#include "qnetworkconfiguration.h" +#include <QHash> +#include <QSharedPointer> +#include <QWeakPointer> +#include <QMutex> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QSharedNetworkSessionManager +{ +public: + static QSharedPointer<QNetworkSession> getSession(QNetworkConfiguration config); + static void setSession(QNetworkConfiguration config, QSharedPointer<QNetworkSession> session); +private: + QHash<QNetworkConfiguration, QWeakPointer<QNetworkSession> > sessions; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + +#endif //QSHAREDNETWORKSESSIONPRIVATE_H + |