QNAM - maintain a weak reference to the QNetworkSession

When handling signals from the session, a pointer is needed.
Also the QNetworkReplyImpl needs to access the manager's session.
So, the manager should have a strong and weak reference.
The strong reference is held during connection establishment.
The weak reference is held all the time, though it will become
null when the session is destroyed in idle.
The non static member function getNetworkSession() is used to
create strong references from the weak reference where required.

Task-number: ou1cimx#1004278
Change-Id: I4b5b36b1d996b98e659d993969006c61b4440c15
Reviewed-by: Martin Petersson <Martin.Petersson@nokia.com>
bb10
Shane Kearns 2012-05-31 16:09:38 +01:00 committed by Qt by Nokia
parent 3580168c3e
commit bae1613c4c
5 changed files with 61 additions and 43 deletions

View File

@ -358,13 +358,14 @@ bool QNetworkAccessBackend::start()
{
#ifndef QT_NO_BEARERMANAGEMENT
// For bearer, check if session start is required
if (manager->networkSession) {
QSharedPointer<QNetworkSession> networkSession(manager->getNetworkSession());
if (networkSession) {
// session required
if (manager->networkSession->isOpen() &&
manager->networkSession->state() == QNetworkSession::Connected) {
if (networkSession->isOpen() &&
networkSession->state() == QNetworkSession::Connected) {
// Session is already open and ready to use.
// copy network session down to the backend
setProperty("_q_networksession", QVariant::fromValue(manager->networkSession));
setProperty("_q_networksession", QVariant::fromValue(networkSession));
} else {
// Session not ready, but can skip for loopback connections
@ -386,7 +387,7 @@ bool QNetworkAccessBackend::start()
#ifndef QT_NO_BEARERMANAGEMENT
// Get the proxy settings from the network session (in the case of service networks,
// the proxy settings change depending which AP was activated)
QNetworkSession *session = manager->networkSession.data();
QNetworkSession *session = networkSession.data();
QNetworkConfiguration config;
if (session) {
QNetworkConfigurationManager configManager;

View File

@ -833,8 +833,9 @@ QNetworkConfiguration QNetworkAccessManager::configuration() const
{
Q_D(const QNetworkAccessManager);
if (d->networkSession)
return d->networkSession->configuration();
QSharedPointer<QNetworkSession> session(d->getNetworkSession());
if (session)
return session->configuration();
else
return QNetworkConfiguration();
}
@ -858,11 +859,12 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
{
Q_D(const QNetworkAccessManager);
if (d->networkSession) {
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
if (networkSession) {
QNetworkConfigurationManager manager;
return manager.configurationFromIdentifier(
d->networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString());
networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString());
} else {
return QNetworkConfiguration();
}
@ -897,7 +899,8 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
{
Q_D(const QNetworkAccessManager);
if (d->networkSession) {
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
if (networkSession) {
// d->online holds online/offline state of this network session.
if (d->online)
return d->networkAccessible;
@ -917,7 +920,14 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
*/
const QWeakPointer<const QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession(const QNetworkAccessManager *q)
{
return q->d_func()->networkSession.toWeakRef();
return q->d_func()->networkSessionWeakRef;
}
QSharedPointer<QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession() const
{
if (networkSessionStrongRef)
return networkSessionStrongRef;
return networkSessionWeakRef.toStrongRef();
}
#endif // QT_NO_BEARERMANAGEMENT
@ -1009,7 +1019,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
return new QDisabledNetworkReply(this, req, op);
}
if (!d->networkSession && (d->initializeSession || !d->networkConfiguration.isEmpty())) {
if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.isEmpty())) {
QNetworkConfigurationManager manager;
if (!d->networkConfiguration.isEmpty()) {
d->createSession(manager.configurationFromIdentifier(d->networkConfiguration));
@ -1116,8 +1126,8 @@ void QNetworkAccessManagerPrivate::_q_replyFinished()
// It will not be destroyed immediately, but rather when the connection cache is flushed
// after 2 minutes.
activeReplyCount--;
if (networkSession && activeReplyCount == 0)
networkSession.clear();
if (networkSessionStrongRef && activeReplyCount == 0)
networkSessionStrongRef.clear();
#endif
}
@ -1294,25 +1304,29 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co
initializeSession = false;
//resurrect weak ref if possible
networkSessionStrongRef = networkSessionWeakRef.toStrongRef();
QSharedPointer<QNetworkSession> newSession;
if (config.isValid())
newSession = QSharedNetworkSessionManager::getSession(config);
if (networkSession) {
if (networkSessionStrongRef) {
//do nothing if new and old session are the same
if (networkSession == newSession)
if (networkSessionStrongRef == newSession)
return;
//disconnect from old session
QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()));
QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
QObject::disconnect(networkSessionStrongRef.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()));
QObject::disconnect(networkSessionStrongRef.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
QObject::disconnect(networkSessionStrongRef.data(), SIGNAL(stateChanged(QNetworkSession::State)),
q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
}
//switch to new session (null if config was invalid)
networkSession = newSession;
networkSessionStrongRef = newSession;
networkSessionWeakRef = networkSessionStrongRef.toWeakRef();
if (!networkSession) {
if (!networkSessionStrongRef) {
online = false;
if (networkAccessible == QNetworkAccessManager::NotAccessible)
@ -1324,18 +1338,19 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co
}
//connect to new session
QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection);
QObject::connect(networkSessionStrongRef.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection);
//QueuedConnection is used to avoid deleting the networkSession inside its closed signal
QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection);
QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
QObject::connect(networkSessionStrongRef.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection);
QObject::connect(networkSessionStrongRef.data(), SIGNAL(stateChanged(QNetworkSession::State)),
q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection);
_q_networkSessionStateChanged(networkSession->state());
_q_networkSessionStateChanged(networkSessionStrongRef->state());
}
void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
{
Q_Q(QNetworkAccessManager);
QSharedPointer<QNetworkSession> networkSession(getNetworkSession());
if (networkSession) {
networkConfiguration = networkSession->configuration().identifier();
@ -1344,7 +1359,8 @@ void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
networkSession.clear();
networkSessionStrongRef.clear();
networkSessionWeakRef.clear();
}
}

View File

@ -78,7 +78,6 @@ public:
proxyFactory(0),
#endif
#ifndef QT_NO_BEARERMANAGEMENT
networkSession(0),
lastSessionState(QNetworkSession::Invalid),
networkAccessible(QNetworkAccessManager::Accessible),
activeReplyCount(0),
@ -120,6 +119,7 @@ public:
#ifndef QT_NO_BEARERMANAGEMENT
void createSession(const QNetworkConfiguration &config);
QSharedPointer<QNetworkSession> getNetworkSession() const;
void _q_networkSessionClosed();
void _q_networkSessionNewConfigurationActivated();
@ -144,7 +144,8 @@ public:
#endif
#ifndef QT_NO_BEARERMANAGEMENT
QSharedPointer<QNetworkSession> networkSession;
QSharedPointer<QNetworkSession> networkSessionStrongRef;
QWeakPointer<QNetworkSession> networkSessionWeakRef;
QNetworkSession::State lastSessionState;
QString networkConfiguration;
QNetworkAccessManager::NetworkAccessibility networkAccessible;

View File

@ -759,7 +759,7 @@ void QNetworkReplyHttpImplPrivate::postRequest()
// Create the HTTP thread delegate
QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
#ifndef QT_NO_BEARERMANAGEMENT
delegate->networkSession = managerPrivate->networkSession;
delegate->networkSession = managerPrivate->getNetworkSession();
#endif
// For the synchronous HTTP, this is the normal way the delegate gets deleted
@ -1505,7 +1505,8 @@ void QNetworkReplyHttpImplPrivate::setResumeOffset(quint64 offset)
bool QNetworkReplyHttpImplPrivate::start()
{
#ifndef QT_NO_BEARERMANAGEMENT
if (!managerPrivate->networkSession) {
QSharedPointer<QNetworkSession> networkSession(managerPrivate->getNetworkSession());
if (!networkSession) {
#endif
postRequest();
return true;
@ -1521,10 +1522,10 @@ bool QNetworkReplyHttpImplPrivate::start()
return true;
}
if (managerPrivate->networkSession->isOpen() &&
managerPrivate->networkSession->state() == QNetworkSession::Connected) {
if (networkSession->isOpen() &&
networkSession->state() == QNetworkSession::Connected) {
Q_Q(QNetworkReplyHttpImpl);
QObject::connect(managerPrivate->networkSession.data(), SIGNAL(usagePoliciesChanged(QNetworkSession::UsagePolicies)),
QObject::connect(networkSession.data(), SIGNAL(usagePoliciesChanged(QNetworkSession::UsagePolicies)),
q, SLOT(_q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies)));
postRequest();
return true;
@ -1547,7 +1548,7 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation()
#ifndef QT_NO_BEARERMANAGEMENT
// Do not start background requests if they are not allowed by session policy
QSharedPointer<QNetworkSession> session(manager->d_func()->networkSession);
QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession());
QVariant isBackground = request.attribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(false));
if (isBackground.toBool() && session && session->usagePolicies().testFlag(QNetworkSession::NoBackgroundTrafficPolicy)) {
QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
@ -1564,10 +1565,9 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation()
// QNetworkAccessManager will call reply->backend->start() again for us when the session
// state changes.
state = WaitingForSession;
QNetworkSession *session = managerPrivate->networkSession.data();
if (session) {
QObject::connect(session, SIGNAL(error(QNetworkSession::SessionError)),
QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection);
if (!session->isOpen()) {
@ -1724,7 +1724,7 @@ void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected()
if (!manager)
return;
QNetworkSession *session = managerPrivate->networkSession.data();
QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession();
if (!session)
return;
@ -1752,7 +1752,7 @@ void QNetworkReplyHttpImplPrivate::_q_networkSessionFailed()
// Abort waiting and working replies.
if (state == WaitingForSession || state == Working) {
state = Working;
QSharedPointer<QNetworkSession> session(manager->d_func()->networkSession);
QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession());
QString errorStr;
if (session)
errorStr = session->errorString();
@ -1837,7 +1837,7 @@ void QNetworkReplyHttpImplPrivate::finished()
if (manager) {
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkSession *session = managerPrivate->networkSession.data();
QSharedPointer<QNetworkSession> session = managerPrivate->getNetworkSession();
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

View File

@ -94,7 +94,7 @@ void QNetworkReplyImplPrivate::_q_startOperation()
#ifndef QT_NO_BEARERMANAGEMENT
// Do not start background requests if they are not allowed by session policy
QSharedPointer<QNetworkSession> session(manager->d_func()->networkSession);
QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession());
QVariant isBackground = backend->request().attribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(false));
if (isBackground.toBool() && session && session->usagePolicies().testFlag(QNetworkSession::NoBackgroundTrafficPolicy)) {
error(QNetworkReply::BackgroundRequestNotAllowedError,
@ -288,7 +288,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected()
if (manager.isNull())
return;
QNetworkSession *session = manager->d_func()->networkSession.data();
QSharedPointer<QNetworkSession> session = manager->d_func()->getNetworkSession();
if (!session)
return;
@ -316,7 +316,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionFailed()
// Abort waiting and working replies.
if (state == WaitingForSession || state == Working) {
state = Working;
QSharedPointer<QNetworkSession> session(manager->d_func()->networkSession);
QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession());
QString errorStr;
if (session)
errorStr = session->errorString();
@ -764,7 +764,7 @@ void QNetworkReplyImplPrivate::finished()
if (!manager.isNull()) {
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkSession *session = manager->d_func()->networkSession.data();
QSharedPointer<QNetworkSession> session (manager->d_func()->getNetworkSession());
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