--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/engine/transport/src/catalogshttpsessionmanagerimpl.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1096 @@
+/*
+* Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include "catalogshttpsessionmanagerimpl.h"
+
+#include <es_sock.h>
+
+#include "catalogshttpoperation.h"
+#include "catalogshttpconfig.h"
+#include "catalogstransportoperationid.h"
+#include "catalogshttpconnectioncreator.h"
+#include "catalogsnetworkmanager.h"
+#include "catalogsutils.h"
+#include "catalogshttputils.h"
+
+#include "catalogsdebug.h"
+
+// 20 minutes
+const TInt KDisconnectionDelayInMicroSeconds = 1000000*60*20;
+
+// 20 seconds after we switch to another APN even if the old one is still
+// up
+const TInt KApSwitchDelay = 1000000*20;
+
+// ======== MEMBER FUNCTIONS ========
+
+CCatalogsNetworkManager* CCatalogsHttpSessionManager::iNetworkManager = NULL;
+
+// ---------------------------------------------------------------------------
+// ResumeOperationCallback, called by CAsyncCallBack
+// ---------------------------------------------------------------------------
+//
+static TInt ResumeOperationCallback( TAny* aData )
+ {
+ DLTRACEIN((""));
+ static_cast<CCatalogsHttpSessionManager*>( aData )->ResumeOperationAction();
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpSessionManager* CCatalogsHttpSessionManager::NewL(
+ CDocumentHandler& aDocHandler )
+ {
+ CCatalogsHttpSessionManager* self = new( ELeave )
+ CCatalogsHttpSessionManager( aDocHandler );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpSessionManager::~CCatalogsHttpSessionManager()
+ {
+ DLTRACEIN((""));
+ Cancel();
+ iConnectionTimer.Close();
+ DeletePtr( iMonitor );
+ iTransactionQueue.Close();
+ iDownloadQueue.Close();
+ iGeneralQueue.Close();
+ iRunningQueue.Close();
+ ReleasePtr( iConnection );
+
+ delete iConnectionCreator;
+ delete iCallback;
+
+ // set as NULL after delete because iNetworkManager is static
+ DeletePtr( iNetworkManager );
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Add a reference
+// ---------------------------------------------------------------------------
+//
+
+void CCatalogsHttpSessionManager::AddRef()
+ {
+ iRefCount++;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Release a reference
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::Release()
+ {
+ DLTRACEIN( ( "" ) );
+ iRefCount--;
+ if ( !iRefCount )
+ {
+ delete this;
+ return 0;
+ }
+ return iRefCount;
+ }
+
+// ---------------------------------------------------------------------------
+// StartOperation
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::StartOperation(
+ MCatalogsHttpOperation* aOperation )
+ {
+ DLTRACEIN((""));
+ DLINFO( ("Operation ID: %i, Type: %i",
+ aOperation->OperationId().Id(), aOperation->OperationType() ) );
+ DASSERT( aOperation );
+
+ UpdateRunningOperations();
+
+ DLINFO(("Running operations: %d, transactions: %d, general: %d",
+ iRunningOperations, iRunningTransactions, iRunningFromGeneral ));
+
+ // Make sure the download is removed from queue
+ RemoveFromQueue( aOperation );
+
+ TBool isRunning = EFalse;
+
+ // Check if the operation can connect either by using the current AP
+ // or by opening a new one
+ TRAPD( err, isRunning = ConnectL( *aOperation ) );
+ if ( err != KErrNone )
+ {
+ DLTRACEOUT(("Error: %d, err"));
+ return err;
+ }
+
+ if ( !isRunning )
+ {
+ DLTRACEOUT(("Not running, adding to queue"));
+ return AddToQueue( aOperation );
+ }
+
+ // Check whether operation belongs to general queue or not
+ if ( aOperation->Config().Priority() > ECatalogsPriorityQueued )
+ {
+ // non-general queues
+ if ( iRunningOperations < KMaxConcurrentOperations )
+ {
+ DLTRACE(("Not general queue"));
+ // Check that transactions leave room for downloads and vice versa
+ if ( ( ( aOperation->OperationType() == ECatalogsHttpTransaction ) &&
+ ( iRunningTransactions < KMaxConcurrentOperations - KMinDownloads ) ) ||
+ ( ( aOperation->OperationType() == ECatalogsHttpDownload ) &&
+ ( iRunningOperations - iRunningTransactions <
+ KMaxConcurrentOperations - KMinTransactions ) ) )
+ {
+
+ iRunningOperations++;
+ if ( aOperation->OperationType() == ECatalogsHttpTransaction )
+ {
+ iRunningTransactions++;
+ }
+
+ DLINFO( ( "Running: %i, TRs: %i", iRunningOperations,
+ iRunningTransactions ) );
+ return iRunningQueue.InsertInAddressOrder( aOperation );
+ }
+ else
+ {
+ DLINFO( ( "Running %i, TRs: %i, DLs: %i", iRunningOperations,
+ iRunningTransactions,
+ iRunningOperations - iRunningTransactions ) );
+ }
+ }
+ else
+ {
+ DLINFO( ( "Running: %i >= Max: %i", iRunningOperations,
+ KMaxConcurrentOperations ) );
+ }
+ }
+ else if ( !iRunningFromGeneral )
+ {
+ // General queue
+ DLTRACE(("Operation from general"));
+ return iRunningQueue.InsertInAddressOrder( aOperation );
+ }
+
+ return AddToQueue( aOperation );
+ }
+
+
+// ---------------------------------------------------------------------------
+// PauseOperation
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::PauseOperation(
+ MCatalogsHttpOperation* aOperation )
+ {
+ DLTRACEIN( ("") );
+ DASSERT( aOperation );
+
+ TInt err = RemoveFromQueue( aOperation );
+ if ( err == KErrNone )
+ {
+ err = iRunningQueue.InsertInAddressOrder( aOperation );
+ ResumeOperation();
+ }
+ else
+ {
+ DLERROR(( "Error %d", err ));
+ }
+
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// CompleteOperation
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::CompleteOperation(
+ MCatalogsHttpOperation* aOperation )
+ {
+ DLTRACEIN( ("Running ops: %d, queues: Run: %d, DL: %d, TR: %d, Gen: %d",
+ iRunningOperations, iRunningQueue.Count(),
+ iDownloadQueue.Count(), iTransactionQueue.Count(),
+ iGeneralQueue.Count() ) );
+
+ // This shouldn't happen unless the operation is canceled before the
+ // connection has been created
+ if ( iConnectedOperation == aOperation )
+ {
+ iConnectedOperation = NULL;
+ if ( iConnection )
+ {
+ // This prevents AP selection queries after the operation
+ // has been canceled.
+ DLTRACE(("Cancel connection creation"));
+ iConnection->Cancel();
+
+ // DLMAIN-545, iConnectionState was left as Disconnecting
+ // which prevented the creation of new connections
+ iConnectionState = ECatalogsConnectionDisconnected;
+
+ // iConnection will be released in ConnectL/destructor
+ }
+ }
+
+ TInt index = iRunningQueue.FindInAddressOrder( aOperation );
+ if ( index != KErrNotFound )
+ {
+ DLTRACE(("Removing from running ops, count after: %d",
+ iRunningQueue.Count() - 1 ));
+
+ iRunningQueue.Remove( index );
+ ResumeOperation();
+ }
+ else
+ {
+ RemoveFromQueue( aOperation );
+ // This ensures that connection timer is started if necessary
+ UpdateRunningOperations();
+ }
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Priority change handler
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::OperationPriorityChanged(
+ MCatalogsHttpOperation* aOperation )
+ {
+ if ( RemoveFromQueue( aOperation ) == KErrNone )
+ {
+ return AddToQueue( aOperation );
+ }
+ return KErrNotFound;
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// Connection creator
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpConnectionCreator& CCatalogsHttpSessionManager::ConnectionCreatorL()
+ {
+ DLTRACEIN((""));
+ if( !iConnectionCreator )
+ {
+ iConnectionCreator = CCatalogsHttpConnectionCreator::NewL();
+ }
+ return *iConnectionCreator;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CCatalogsNetworkManager& CCatalogsHttpSessionManager::NetworkManagerL()
+ {
+ DLTRACEIN((""));
+ if ( !iNetworkManager )
+ {
+ iNetworkManager = CCatalogsNetworkManager::NewL();
+ }
+ return *iNetworkManager;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CDocumentHandler& CCatalogsHttpSessionManager::DocumentHandler()
+ {
+ return iDocHandler;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::SetResumeMode( TBool aResumeQueued )
+ {
+ iResumeQueued = aResumeQueued;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::RunL()
+ {
+ DLTRACEIN(("iStatus: %d", iStatus.Int() ));
+ if ( iStatus.Int() == KErrNone )
+ {
+ if ( iConnection )
+ {
+ DLTRACE(("Idle timeout, releasing connection"));
+ DASSERT( iConnection && iConnection->RefCount() == 1 );
+ // Monitor is deleted elsewhere
+ if ( iMonitor )
+ {
+ iMonitor->Cancel();
+ }
+
+ NetworkManagerL().CloseAccessPointL( iConnection->ConnectionMethod() );
+ // We don't need to monitor the shutdown because we're not
+ // switching to an another APN
+ ReleasePtr( iConnection );
+ iConnectionState = ECatalogsConnectionDisconnected;
+ }
+ else if ( iSwitchApTimer )
+ {
+ iSwitchApTimer = EFalse;
+ // emulate real connection shutdown
+ ConnectionStateChangedL( KConnectionUninitialised );
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::DoCancel()
+ {
+ DLTRACEIN((""));
+ iConnectionTimer.Cancel();
+ iSwitchApTimer = EFalse;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::RunError( TInt aError )
+ {
+ DLTRACEIN(("aError: %d", aError ));
+ (void) aError;
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// CCatalogsHttpSessionManager
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpSessionManager::CCatalogsHttpSessionManager(
+ CDocumentHandler& aDocHandler ) :
+ CActive( CActive::EPriorityStandard ),
+ iRefCount( 1 ),
+ iResumeQueued( ETrue ),
+ iDocHandler( aDocHandler )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+
+// ---------------------------------------------------------------------------
+// ResumeOperation
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ResumeOperation()
+ {
+ DLTRACEIN((""));
+ DLINFO( ( "Tr queue: %i, Dl queue: %i, general: %i",
+ iTransactionQueue.Count(),
+ iDownloadQueue.Count(),
+ iGeneralQueue.Count() ) );
+
+ if ( !iResumeQueued )
+ {
+ DLTRACEOUT(("Operation resuming disabled"));
+ return;
+ }
+
+ DLTRACE(("Callback"))
+ if ( !iCallback->IsActive() )
+ {
+ iResumeCount++;
+ iCallback->CallBack();
+ }
+ else
+ {
+ iResumeCount++;
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ResumeOperationAction
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::ResumeOperationAction()
+ {
+ DLTRACEIN((""));
+
+ RCatalogsHttpOperationArray* array = NULL;
+ UpdateRunningOperations();
+
+ if ( !iRunningFromGeneral && iGeneralQueue.Count() )
+ {
+ array = &iGeneralQueue;
+ }
+ else if ( iTransactionQueue.Count() && ( iDownloadQueue.Count() == 0 ||
+ iTransactionQueue[0]->Config().Priority() >=
+ iDownloadQueue[0]->Config().Priority() ) )
+ {
+ DLTRACE( ("Resuming transaction") );
+ // Resume transaction
+ array = &iTransactionQueue;
+ }
+ else if ( iDownloadQueue.Count() )
+ {
+ DLTRACE( ("Resuming download") );
+ // Resume download
+ array = &iDownloadQueue;
+ }
+
+
+ if ( array )
+ {
+ iResumeCount--;
+ if ( iResumeCount )
+ {
+ DLTRACE(("Call resume callback again"));
+ iCallback->CallBack();
+ }
+
+ MCatalogsHttpOperation* operation = (*array)[0];
+ DLTRACE( ( "Resuming: %x, type: %i, id: %i",
+ operation, operation->OperationType(),
+ operation->OperationId().Id() ) );
+
+ // Start will remove the operation
+ return operation->Start( MCatalogsHttpOperation::EAutomaticResume );
+ }
+
+ iResumeCount = 0;
+ DLTRACE( ( "Nothing to resume" ) );
+ return KErrNotFound;
+ }
+
+
+// ---------------------------------------------------------------------------
+// ConnectionCreatedL
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ConnectionCreatedL(
+ const TCatalogsConnectionMethod& aMethod )
+ {
+ DLTRACEIN(("method: %d, %u, %u",
+ aMethod.iType, aMethod.iId, aMethod.iApnId ));
+
+ StartMonitoringL( EFalse );
+ iLatestConnectionMethod = aMethod;
+ iConnectionState = ECatalogsConnectionConnected;
+
+ // Update connection to queued operations that require it
+ SetConnectionToQueue(
+ aMethod,
+ iDownloadQueue );
+
+ SetConnectionToQueue(
+ aMethod,
+ iTransactionQueue );
+
+ SetConnectionToQueue(
+ aMethod,
+ iGeneralQueue );
+
+ DLTRACE(("Starting the operation"));
+
+ if ( iConnectedOperation )
+ {
+ MCatalogsHttpOperation* connect = iConnectedOperation;
+ iConnectedOperation = NULL;
+ User::LeaveIfError( connect->Start() );
+ }
+
+ // Try to fill the running queue by resuming queued operations
+ iResumeCount = KMaxConcurrentOperations - 1;
+ ResumeOperation();
+
+ NetworkManagerL().OpenAccessPointL( aMethod );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Sets current connection to those operations that have a matching
+// connection method
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::SetConnectionToQueue(
+ const TCatalogsConnectionMethod& aMethod,
+ RCatalogsHttpOperationArray& aArray )
+ {
+ DASSERT( iConnection );
+ TInt count = aArray.Count();
+ while ( count-- )
+ {
+ if ( aArray[ count ]->Config().ConnectionMethod().Match( aMethod ) )
+ {
+ aArray[ count ]->SetConnection( *iConnection );
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ConnectionError
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ConnectionError( TInt aError )
+ {
+ DLTRACEIN(("error: %d", aError ));
+ iConnectionState = ECatalogsConnectionDisconnected;
+ Cancel();
+ // notify operations about failure
+
+ ReportConnectionError(
+ iConnection->ConnectionMethod(),
+ iDownloadQueue,
+ aError );
+
+ ReportConnectionError(
+ iConnection->ConnectionMethod(),
+ iTransactionQueue,
+ aError );
+
+ ReportConnectionError(
+ iConnection->ConnectionMethod(),
+ iGeneralQueue,
+ aError );
+
+ iConnectedOperation = NULL;
+
+
+ // Try to resume remaining operations in case they get lucky
+ ReleasePtr( iConnection );
+ iResumeCount = 0;
+ ResumeOperation();
+ }
+
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ConnectionStateChangedL( TInt aStage )
+ {
+ DLTRACEIN(("aStage: %d", aStage ));
+
+ if ( aStage == KConnectionUninitialised )
+ {
+ DLTRACE(("Resuming operations"));
+ Cancel();
+
+ if ( iMonitor )
+ {
+ // Monitor is deleted elsewhere
+ iMonitor->Cancel();
+ }
+
+ iConnectionState = ECatalogsConnectionDisconnected;
+ NetworkManagerL().NotifyAccessPointReallyClosedL(
+ iLatestConnectionMethod );
+
+ // no point resuming more than one op since it needs to create
+ // the connection before other operations can be resumed
+ iResumeCount = 0;
+ ResumeOperation();
+ }
+ else if ( aStage == KErrConnectionTerminated )
+ {
+ DLTRACE(("Connection error: %d", aStage ));
+
+ if ( iMonitor )
+ {
+ // Monitor is deleted elsewhere
+ iMonitor->Cancel();
+ }
+
+ iConnectionState = ECatalogsConnectionDisconnecting;
+ NetworkManagerL().NotifyAccessPointReallyClosedL(
+ iLatestConnectionMethod );
+
+ // notify operations about failure
+ SetResumeMode( EFalse );
+
+ ReportConnectionError(
+ iRunningQueue,
+ aStage );
+
+ ReportConnectionError(
+ iDownloadQueue,
+ aStage );
+
+ ReportConnectionError(
+ iTransactionQueue,
+ aStage );
+
+ ReportConnectionError(
+ iGeneralQueue,
+ aStage );
+
+ TCatalogsConnectionMethod method;
+ if ( iConnection )
+ {
+ method = iConnection->ConnectionMethod();
+ }
+ NetworkManagerL().CloseAccessPointL( method );
+
+ SetResumeMode( ETrue );
+ iConnectedOperation = NULL;
+
+ iConnectionState = ECatalogsConnectionDisconnected;
+ Cancel();
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ConnectionStateError( TInt aError )
+ {
+ DLTRACEIN(("aError: %d", aError ));
+ (void) aError;
+ iConnectionState = ECatalogsConnectionDisconnected;
+ Cancel();
+ // Just try to resume an operation, nothing else we can do
+ iResumeCount = 0;
+ ResumeOperation();
+
+ }
+
+
+// ---------------------------------------------------------------------------
+// ReportConnectionError
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ReportConnectionError(
+ const TCatalogsConnectionMethod& aMethod,
+ RCatalogsHttpOperationArray& aArray,
+ TInt aError )
+ {
+ TInt count = aArray.Count();
+ while ( count-- )
+ {
+ // iConnectedOperation-pointer is used to ensure that at least it
+ // is notified even if the connection method would have changed
+ // for some reason
+ if ( aArray[ count ]->Config().ConnectionMethod().Match( aMethod ) ||
+ aArray[ count ] == iConnectedOperation )
+ {
+ aArray[ count ]->ReportConnectionError( aError );
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ReportConnectionError
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ReportConnectionError(
+ RCatalogsHttpOperationArray& aArray,
+ TInt aError )
+ {
+ TInt count = aArray.Count();
+ while ( count-- )
+ {
+ aArray[ count ]->ReportConnectionError( aError );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// AddToQueue
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::AddToQueue(
+ MCatalogsHttpOperation* aOperation )
+ {
+ DLTRACEIN((""));
+ DLINFO( ( "Operation ID: %i, Type: %i",
+ aOperation->OperationId().Id(), aOperation->OperationType() ) );
+
+ // Insert the operation in priority order
+ TLinearOrder<MCatalogsHttpOperation> order(
+ &CCatalogsHttpSessionManager::PrioritizeOperations );
+
+ TInt err = ChooseArray( *aOperation ).InsertInOrderAllowRepeats(
+ aOperation, order );
+ if ( err != KErrNone )
+ {
+ DLTRACE( ( "Failed with err: %i", err ) );
+ return err;
+ }
+
+ DLINFO( ( "After Add, Queued TRs: %i, DLs: %i" ,
+ iTransactionQueue.Count(), iDownloadQueue.Count() ) );
+
+ return KCatalogsHttpOperationQueued;
+ }
+
+
+// ---------------------------------------------------------------------------
+// RemoveFromQueue
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::RemoveFromQueue(
+ MCatalogsHttpOperation* aOperation )
+ {
+ DLTRACEIN((""));
+
+ if ( aOperation == iConnectedOperation )
+ {
+ iConnectedOperation = NULL;
+ }
+
+ TInt index = iRunningQueue.Find( aOperation );
+ if ( index != KErrNotFound )
+ {
+ iRunningQueue.Remove( index );
+ DLTRACEOUT(("Removed from running"));
+ return KErrNone;
+ }
+
+ RCatalogsHttpOperationArray& array = ChooseArray( *aOperation );
+
+ index = array.Find( aOperation );
+ if ( index != KErrNotFound )
+ {
+ array.Remove( index );
+ DLINFO( ( "After Remove, Queued TRs: %i, DLs: %i" ,
+ iTransactionQueue.Count(), iDownloadQueue.Count() ) );
+
+ return KErrNone;
+ }
+ return KErrNotFound;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Compares the priorities of two operations
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpSessionManager::PrioritizeOperations(
+ const MCatalogsHttpOperation& aFirst,
+ const MCatalogsHttpOperation& aSecond )
+ {
+ return aFirst.Config().Priority() - aSecond.Config().Priority();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Choose array
+// ---------------------------------------------------------------------------
+//
+RCatalogsHttpOperationArray& CCatalogsHttpSessionManager::ChooseArray(
+ const MCatalogsHttpOperation& aOperation )
+ {
+ DLTRACEIN((""));
+ if ( aOperation.Config().Priority() <= ECatalogsPriorityQueued )
+ {
+ DLTRACEOUT(("Queued general"));
+ return iGeneralQueue;
+ }
+
+ if ( aOperation.OperationType() == ECatalogsHttpTransaction )
+ {
+ DLTRACEOUT(("Queued transaction"));
+ return iTransactionQueue;
+ }
+
+ DLTRACEOUT(("Queued download"));
+ return iDownloadQueue;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::UpdateRunningOperations()
+ {
+ DLTRACEIN((""));
+ const TTimeIntervalMicroSeconds32 KDisconnectionDelay(
+ KDisconnectionDelayInMicroSeconds );
+
+ iRunningDownloads = 0;
+ iRunningTransactions = 0;
+ iRunningFromGeneral = 0;
+ for ( TInt i = 0; i < iRunningQueue.Count(); ++i )
+ {
+ if ( iRunningQueue[i]->Config().Priority() <= ECatalogsPriorityQueued )
+ {
+ iRunningFromGeneral++;
+ }
+ else if ( iRunningQueue[i]->OperationType() == ECatalogsHttpTransaction )
+ {
+ iRunningTransactions++;
+ }
+ else if ( iRunningQueue[i]->State() !=
+ ECatalogsHttpOpPaused )
+ {
+ iRunningDownloads++;
+ }
+ }
+
+ iRunningOperations = iRunningTransactions + iRunningDownloads;
+
+ // Handle connection timer: either cancel it if we have running operations
+ // or start it if it's not running already
+ if ( iRunningOperations + iRunningFromGeneral )
+ {
+ Cancel();
+ }
+ else if ( !IsActive() && iConnection )
+ {
+ DLTRACE(("Starting timer, time: %d",
+ KDisconnectionDelayInMicroSeconds ));
+ iSwitchApTimer = EFalse;
+ // Using RTimer instead of RConnectionMonitor because we can't
+ // observe the RConnection used by Download manager
+ iConnectionTimer.After( iStatus, KDisconnectionDelay );
+ SetActive();
+ }
+
+ DLTRACEOUT(("Running dls: %d, trs: %d, paused dls: %d, general: %d",
+ iRunningDownloads,
+ iRunningTransactions,
+ iRunningQueue.Count() - iRunningDownloads - iRunningTransactions,
+ iRunningFromGeneral ));
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpSessionManager::ConstructL()
+ {
+ DLTRACEIN((""));
+ iCallback = new (ELeave) CAsyncCallBack(
+ TCallBack( ResumeOperationCallback, this ),
+ CActive::EPriorityStandard );
+ User::LeaveIfError( iConnectionTimer.CreateLocal() );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpSessionManager::ConnectL( MCatalogsHttpOperation& aOperation )
+ {
+ DLTRACEIN((""));
+ DLMETHOD( aOperation.Config().ConnectionMethod() );
+
+#ifdef CATALOGS_BUILD_CONFIG_DEBUG
+ if ( iConnection )
+ {
+ DLINFO(("Connection refcount: %d", iConnection->RefCount() ));
+ DLMETHOD( iConnection->ConnectionMethod() );
+ }
+#endif
+
+ // We must not cancel the timer if we are waiting for the old connection
+ // to go down because that same timer is used for switching to new
+ // AP after a timeout.
+ if ( !iSwitchApTimer )
+ {
+ Cancel();
+ }
+
+ // Don't even try to connect when connection is going up or down
+ if ( iConnectionState == ECatalogsConnectionConnecting ||
+ iConnectionState == ECatalogsConnectionDisconnecting )
+ {
+ DLTRACEOUT(("(Dis)connecting..., cannot resume now"));
+ return EFalse;
+ }
+
+ // Check that the connection is still alive
+ TBool connected = EFalse;
+ if ( iConnection )
+ {
+ connected = iConnection->IsConnectedL();
+ }
+
+ // If there's a connection and it matches the wanted connection we can just
+ // use that
+ if ( connected )
+ {
+ DLTRACE(( "Connected" ));
+ const TCatalogsConnectionMethod& newMethod(
+ aOperation.Config().ConnectionMethod() );
+ const TCatalogsConnectionMethod& currentMethod(
+ iConnection->ConnectionMethod() );
+
+ // We accept an connection if either type and id match
+ // or the connected APN matches with the wanted one
+ if ( newMethod.Match( currentMethod ) ||
+ ( currentMethod.iApnId != 0 &&
+ ( newMethod.iApnId == currentMethod.iApnId ||
+ ( newMethod.iType == ECatalogsConnectionMethodTypeAccessPoint &&
+ newMethod.iId == currentMethod.iApnId ) ) ) )
+ {
+ // Update connected operation in case the old one has been released
+ iConnectedOperation = &aOperation;
+ DLTRACE(("Not connected, setting connection"));
+ aOperation.SetConnection( *iConnection );
+
+ return ETrue;
+ }
+ }
+
+
+ if ( DisconnectL() )
+ {
+ // connection was on so we don't want to recreate a new one until
+ // the old one has gone down
+ return EFalse;
+ }
+
+
+ if ( !iConnection )
+ {
+ DLTRACE(("Creating a new connection"));
+ DeletePtr( iMonitor );
+ // create connection
+ iConnection = CCatalogsConnection::NewL(
+ ConnectionCreatorL(),
+ aOperation.ConnectionManager(),
+ *this );
+
+ iConnectedOperation = &aOperation;
+ iConnection->ConnectL( aOperation.Config().ConnectionMethod() );
+ iConnectionState = ECatalogsConnectionConnecting;
+ }
+
+ return EFalse;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpSessionManager::StartMonitoringL( TBool aStartSwitchTimer )
+ {
+ DLTRACEIN((""));
+ DeletePtr( iMonitor );
+
+ TUint count = 0;
+
+ // RConnection may have been closed already if an operation was canceled
+ // before the connection was created
+ if ( !iConnection->Connection().SubSessionHandle() )
+ {
+ DLTRACEOUT(("Connection has been closed already"));
+ return EFalse;
+ }
+
+ User::LeaveIfError( iConnection->Connection().EnumerateConnections( count ) );
+ TConnectionInfoBuf connectionBuf;
+ TBool open = CatalogsHttpUtils::IsConnectionMethodOpen(
+ iConnection->Connection(),
+ count,
+ iConnection->ConnectionMethod(),
+ connectionBuf );
+
+ // We don't start monitoring unless the connection is up because we
+ // wouldn't get any progress notifications if it is already down
+ if ( open )
+ {
+ iMonitor = CCatalogsConnectionMonitor::NewL( *this );
+
+ DLTRACE(("Start monitoring for connection shutdown"));
+ iMonitor->StartL( connectionBuf );
+
+ if ( aStartSwitchTimer )
+ {
+ Cancel();
+ iSwitchApTimer = ETrue;
+ // Initiate delay after which we switch to new AP even if we the old
+ // connection hasn't closed yet
+ iConnectionTimer.After( iStatus, KApSwitchDelay );
+ SetActive();
+ }
+
+ // Prevent operation from starting by returning EFalse
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+
+TBool CCatalogsHttpSessionManager::DisconnectL()
+ {
+ DLTRACEIN((""));
+ // If the connection is not used anymore we can release it so that a new
+ // one can be created
+ if ( iConnection &&
+ iConnection->RefCount() == 1 )
+ {
+ DLTRACE(("Releasing unused connection"));
+ NetworkManagerL().CloseAccessPointL( iConnection->ConnectionMethod() );
+
+ // Starts monitoring the connection shutdown if the connection is up
+ if ( StartMonitoringL( ETrue ) )
+ {
+ DLTRACE(("Stopping the connection"));
+ iConnectionState = ECatalogsConnectionDisconnecting;
+ ReleasePtr( iConnection );
+
+ return ETrue;
+ }
+
+ DLTRACE(("Connection was not open"));
+ iConnectionState = ECatalogsConnectionDisconnected;
+ // Connection was not open, we can try to connect straight away
+ ReleasePtr( iConnection );
+ }
+ return EFalse;
+ }