ncdengine/engine/transport/src/catalogshttpsessionmanagerimpl.cpp
changeset 0 ba25891c3a9e
child 25 7333d7932ef7
--- /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;
+    }