IMPSengine/engsrv/src/impsactiveconnmonitor.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:41:52 +0200
changeset 0 094583676ce7
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2003-2005 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: Imps connection manager.
*
*
*/




// INCLUDE FILES
#include    <e32std.h>
#include    "ImpsSendReceive.h"
#include    "impsactiveconnmonitor.h"
#include    "impsutils.h"
#include    "impserrors.h"


// CONSTANTS

// MACROS
#ifndef _DEBUG
#define _NO_IMPS_LOGGING_
#endif

// LOCAL CONSTANTS AND MACROS

// Wait time 8 seconds before IAP re-opened
const TInt KImpsWaitIAPOpen = 8000000;



// ================= MEMBER FUNCTIONS =======================

// C++ default constructor can NOT contain any code, that
// might leave.
//

//**********************************
// CImpsConnManager
//**********************************
CImpsConnManager::CImpsConnManager(
    CImpsSendReceive2& aSender,
    TInt aPriority )
        : CActive( aPriority ),
        iSender( aSender ),
        iState( EImpsNoAP ),
        iCmd( EImpsTransNone ),
        iConnState( EMsgBearerActive ),
        iManager( NULL ),
        iRunL( EFalse )
    {
    ( void ) iTimer.CreateLocal();
    // Add this to the scheduler
    CActiveScheduler::Add( this );
    }

// EPOC default constructor can leave.
void CImpsConnManager::ConstructL()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: CONSTRUCTL rel200540.3f cman=%d" ), ( TInt )this );
#endif
    iManager = NewMsgConnManagerL( 0 );
    }

// Two-phased constructor.
CImpsConnManager* CImpsConnManager::NewL(
    CImpsSendReceive2& aSender, TInt aPriority )
    {
    CImpsConnManager* self = new ( ELeave ) CImpsConnManager(
        aSender, aPriority );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }


// Destructor
CImpsConnManager::~CImpsConnManager()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: DESTRUCTOR begins cman=%d" ), ( TInt )this );
#endif
    Cancel();
    iTimer.Close();
    if ( iManager )
        {
        iManager->Destroy();
        }

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: DESTRUCTOR ends cman=%d" ), ( TInt )this );
#endif
    }

// ---------------------------------------------------------
// CImpsConnManager::OpenAPL
// ---------------------------------------------------------
//
void CImpsConnManager::OpenAPL(
    TInt  aIAP, TBool aDelayed )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: OpenAPL iap=%d delay=%d cman=%d" ),
                            aIAP, aDelayed, ( TInt )this );
#endif
    if ( IsActive () )
        {
        // Notice: We should not be here
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CImpsConnManager: BUSY cman=%d ****" ), ( TInt )this );
#endif
        User::Leave( KErrNotReady );
        }

    iConnState = EMsgBearerActive;

    if ( ( aDelayed || iRunL ) && iCmd != EImpsTransWaitOpen )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d OpenAPL extra wait ****" ), ( TInt )this );
#endif
        iCmd = EImpsTransWaitOpen;
        iState = EImpsNoAP;
        iIAP = aIAP;
        SetActive();
        // Give time for Connection Manager
        iTimer.After( iStatus, KImpsWaitIAPOpen );
        return;
        }
    iCmd = EImpsTransNone;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d calls SetAccessPointIDL" ), ( TInt )this );
#endif
    iManager->SetAccessPointIDL( aIAP );
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d calls RemoveEventSubscriber and AddEventSubscriberL" ), ( TInt )this );
#endif
    // Verify that in error cases nothing is left hanging
    iManager->RemoveEventSubscriber( this );
    iManager->AddEventSubscriberL( this );
    iStatus = KRequestPending;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d calls StartConnection" ), ( TInt )this );
#endif
    iManager->StartConnection( iStatus );
    iCmd = EImpsTransOpenAP;
    iState = EImpsNoAP;
    iIAP = aIAP;
    SetActive();
    }

// ---------------------------------------------------------
// CImpsConnManager::CloseAP
// ---------------------------------------------------------
//
void CImpsConnManager::CloseAP( TBool /*aTotalClose*/ )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: CloseAP state=%d %d cman=%d" ),
                            iState, IsActive(), ( TInt )this );
#endif

    if ( iState == EImpsNoAP && !IsActive() )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d CloseAP already closed" ), ( TInt )this );
#endif
        iCmd = EImpsTransNone;
        iConnState = EMsgBearerActive;
        // Engine core waits any kind of response in shut down
        iSender.APStatusEvent( EImpsNoAP, KErrNone, ETrue );
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d CloseAP ends" ), ( TInt )this );
#endif
        return;
        }
    else if ( iState == EImpsNoAP && IsActive() )
        {
        // Waiting open timer must be cancelled
        if ( iCmd == EImpsTransWaitOpen )
            {
            // This cancels the timer
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d err: CANCEL ***" ), ( TInt )this );
#endif
            Cancel();
            iCmd = EImpsTransCloseAP;
            iIAP = 0;
            // Now do the trick to go to own RunL and call there appropriate callback.
            ActivateMe();
            return;
            }
        else if ( iCmd == EImpsTransOpenAP )
            {
            // Open APL is pending and must be cancelled
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d calls CancelStartL ****" ), ( TInt )this );
#endif
            TRAPD( errx, iManager->CancelStartL() );
            if ( errx )
                {
                // Normally this is not needed, but Cancel StartL may leave with
                // KErrAbort if there is no pending request.
                // VERY RARE situation.
                iCmd = EImpsTransNone;
                iSender.APStatusEvent( EImpsNoAP, KErrNone, ETrue );
                return;
                }
            // Normal case continues in RunL
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d CloseAP ends" ), ( TInt )this );
#endif
            return;
            }
        }
    else if ( IsActive() )  //
        {
        // Previous close is not completed.
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d BUSY ***" ), ( TInt )this );
#endif
        return;
        }
    iCmd = EImpsTransCloseAP;
    iIAP = 0;
    iStatus = KRequestPending;
    SetActive();
    // Notice: Rest of activities in RunL and destructor
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d calls RemoveEventSubscriber" ), ( TInt )this );
#endif
    iManager->RemoveEventSubscriber( this );
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d calls StopConnection" ), ( TInt )this );
#endif
    iManager->StopConnection( iStatus );

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d CloseAP ends" ), ( TInt )this );
#endif
    }


// ---------------------------------------------------------
// CImpsConnManager::HandleBearerEventL
// ---------------------------------------------------------
//
void CImpsConnManager::HandleBearerEventL( TBool aIsAuthClose, TMsgBearerEvent aBearerEvent )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log(
        _L( "CImpsConnManager: HandleBearerEventL %d authClose=%d cman=%d" ), aBearerEvent, aIsAuthClose, ( TInt )this );
#endif
    iConnState = aBearerEvent;
    if ( IsActive() )
        {
        // pending open/close, so wait that instead
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log(
            _L( "CImpsConnManager: HandleBearerEventL SPECIAL cmd=%d cman=%d ***" ), iCmd, ( TInt )this );
#endif

        /* Notice:
         This is a little bit tricky situation because of Msg ConnManager DLL
         cannot quarantee the right order of events for us! Thus it is
         possible that we first get bearer-event and after that response
         for open/close connection request although the actual order
         is that open/close is first completed and then the bearer event has
         taken a place.

               /@
               \ \
             ___> \
            (__O)  \
           (____@)  \
           (____@)   \
            (__o)_    \
                  \    \
        */

        switch ( iConnState )
            {
            case EMsgBearerActive:
                iSender.APStatusEvent( EImpsOnline, KErrNone, EFalse );
                break;
            case EMsgBearerSuspended:
                iSender.APStatusEvent( EImpsOffline, KErrNone, EFalse );
                break;
            case EMsgBearerLost:
            default:
                {
                // RunL handles rest of the activities
                // when iConnState == EMsgBearerLost.
                break;
                }
            };
        }
    else // regular case
        {
        switch ( iConnState )
            {
            case EMsgBearerActive:
                iSender.APStatusEvent( EImpsOnline, KErrNone, EFalse );
                break;
            case EMsgBearerSuspended:
                iSender.APStatusEvent( EImpsOffline, KErrNone, EFalse );
                break;
            case EMsgBearerLost:
            default:
                {
                iState = EImpsNoAP;
                iSender.APStatusEvent( EImpsNoAP, KErrNone, EFalse, aIsAuthClose );
                break;
                }
            }
        };
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d HandleBearerEventL ends" ), ( TInt )this );
#endif
    }

// ---------------------------------------------------------
// CImpsConnManager::ManagerHandleL
// ---------------------------------------------------------
//
MMsgConnManager& CImpsConnManager::ManagerHandleL() const
    {
    if ( !iManager )
        {
        User::Leave( KErrBadHandle );
        }
    return *iManager;
    }

// ---------------------------------------------------------
// CImpsConnManager::Destroy
// ---------------------------------------------------------
//
void CImpsConnManager::Destroy()
    {
    if ( iManager )
        {
        iManager->Destroy();
        }
    iManager = NULL;
    }

// ---------------------------------------------------------
// CImpsConnManager::RunL
// ---------------------------------------------------------
//
void CImpsConnManager::RunL( )
    {

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: RunL ret=%d cmd=%d state=%d conn=%d cman=%d" ),
                            iStatus.Int(), iCmd, iState, iConnState, ( TInt )this );
#endif

    iRunL = ETrue;
    TInt ret = iStatus.Int();

    // We have delayed and given time for connection manager to work properly
    if ( iCmd == EImpsTransWaitOpen )
        {
        if ( !ret )
            {
            TInt errx = KErrNone;
            TRAP( errx, OpenAPL( iIAP, EFalse ) );
            }
        else
            {
            iState = EImpsNoAP;
            iCmd = EImpsTransNone;
            iSender.APStatusEvent( iState, ret, ETrue );
            }
        }
    else if ( iCmd == EImpsTransOpenAP )
        {
        iCmd = EImpsTransNone;
        iState = EImpsNoAP;
        if ( ret == KErrNone )
            {
            if ( iConnState != EMsgBearerLost )
                {
                // AP is opened successfully
                iState = EImpsOnline;
                }
            else // iConnState == EMsgBearerLost
                {
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CImpsConnManager: err: cman=%d iConnState==EMsgBearerLost ****" ), ( TInt )this );
#endif
                // Special case where order of events from ConnManager is not valid.
                ret = KImpsErrorNoIAP;
                // KImpsErrorNoIAP error code has a special error handling
                // in CSPSession class.
                }
            }
        iSender.APStatusEvent( iState, ret, ETrue );
        }
    else if ( iCmd == EImpsTransCloseAP )
        {
        iCmd = EImpsTransNone;
        iState = EImpsNoAP;
        // Notice that iSender must exist, i.e. DeleteCSP() cancels
        // everything before deleting CSP session entity referred by iSender.
        iSender.APStatusEvent( EImpsNoAP, ret, ETrue );
        }
    else if ( iCmd == EImpsTransCloseDelay )
        {
        // This is a special case where this object is used for yielding.
        // Actually it calls CloseAP
        iCmd = EImpsTransNone;
        iSender.CloseTr( );
        }
    else
        {
        iCmd = EImpsTransNone;
        }
    iRunL = EFalse;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d RunL ends" ), ( TInt )this );
#endif
    }

// ---------------------------------------------------------
// CImpsConnManager::DoCancel
// ---------------------------------------------------------
//
void CImpsConnManager::DoCancel()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d DoCancel" ), ( TInt )this );
#endif
    TImpsTransCmd orig = iCmd;
    iCmd = EImpsTransNone;
    if ( orig == EImpsTransOpenAP )
        {
        // cancel
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d calls CancelStartL *****" ), ( TInt )this );
#endif
        TInt errx = KErrNone;
        TRAP( errx, iManager->CancelStartL() );
        }
    else if ( orig == EImpsTransCloseAP )
        {
        iState = EImpsNoAP;
        }
    // This just waits IAP connection operation to end.
    else if ( iCmd == EImpsTransWaitOpen )
        {
        iTimer.Cancel();
        }
    }

TInt CImpsConnManager::ActivateMe(  )
    {
    // This yields the control to the server thread active scheduler
    if ( !IsActive() )
        {
        iStatus = KRequestPending;
        SetActive();
        TRequestStatus* s = &iStatus;
        User::RequestComplete( s, KErrNone );
        return KErrNone;
        }
    else
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d KErrNotReady ****" ), ( TInt )this );
#endif
        return KErrNotReady;
        }
    }

TInt CImpsConnManager::StartDelayed( )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CImpsConnManager: cman=%d StartDelayed" ), ( TInt )this );
#endif
    iCmd = EImpsTransCloseDelay;
    return ActivateMe();
    }


//  End of File