alwayson_net_plugin/pdpcontextmanager2/src/caoconnectionimpl.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 26 Jan 2010 12:12:48 +0200
changeset 3 f7816ffc66ed
parent 0 5a93021fdf25
permissions -rw-r--r--
Revision: 201001 Kit: 201004

/*
* Copyright (c) 2004,2006 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:  Implements the CAOConnectionImpl class
*
*/


// INCLUDE FILES
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <es_enum_partner.h>
#endif
#include <es_enum.h>
#include <etelpckt.h>
#include <in_sock.h>

#include "caoconnectionimpl.h"
#include "maosettings.h"
#include "logger.h"
#include "maoconnectionobserver.h"

// UNNAMED NAMESPACE FOR LOCAL DEFINITIONS
namespace
    {
    // CONSTANTS
    _LIT( KPanicCat, "ConnectionImpl" );
    
    // DATA TYPES
    enum TPanicCode
        {
        ENone,
        EConnectionAlreadyActive,
        ENotActive,
        EInvalidState,
        EAlreadyActive,
        EReuqestNotPending
        };
    
    // LOCAL FUNCTIONS
    LOCAL_C void Panic( TPanicCode aCode )
        {
        User::Panic( KPanicCat, aCode );
        }
    }

// METHODS

// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CAOConnectionImpl* CAOConnectionImpl::NewL(
    MAOConnectionObserver& aObserver,
    MAOSettings&           aSettings,
    RSocketServ*           aSocketServ )
    {
    LOG_1( _L("CAOConnectionImpl::NewL") );
    
    CAOConnectionImpl* self = new( ELeave ) CAOConnectionImpl(
        aObserver,
        aSettings,
        aSocketServ );
    
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
        
    return self;
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CAOConnectionImpl::~CAOConnectionImpl()
    {
    LOG_1( _L("CAOConnectionImpl::~CAOConnectionImpl") );
    
    Cancel();
    
    delete iCommsDatabase;
    iConnection.Close();
    
    delete iExtPrefs;
    delete iPrefsList;
    }


// ---------------------------------------------------------------------------
// CAOConnectionImpl::ActivateConnection
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::ActivateConnection()
    {
    LOG_1( _L("CAOConnectionImpl::ActivateConnection") );
        
    __ASSERT_DEBUG( !IsActive() && iState == EDisconnected,
        Panic( EConnectionAlreadyActive ) );
        
    // Change state to EOpeningLink
    ChangeState( EOpeningLink );
    
    // Check IAP
    TUint iap = iSettings.AccessPointId();
    if ( IsValidIAP( iap ) && iSettings.IsCellularAllowedByUser() )
        {
        // Check that we really have RConnection handle opened
        TInt err = KErrNone;
        if( !iConnection.SubSessionHandle() )
            {
            // Socket serv is closed only in destructor
            err = iConnection.Open( *iSocketServ );
            }
    
        if( err == KErrNone )
            {    		
            // Start as a silent connection
            iExtPrefs->SetIapId( iap );
            iExtPrefs->SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent );
    		
            // Clean iPrefsList and append new prefs
            iPrefsList->Remove( 0 );
            TRAPD( err, iPrefsList->AppendL( iExtPrefs ) )
    		
            if ( err == KErrNone )
                {
    		    iConnection.Start( *iPrefsList, iStatus );
                SetActive();
                }
            else
                {
                LOG_1( _L("iPrefsList->AppendL( iExtPrefs ) FAILED") );
                ActivateSelf( KErrNotSupported );
                }
            }
        else
            {
            ActivateSelf( KErrNotSupported );
            }
        }
    else
        {
        // Something is wrong. Complete self with error KErrNotSupported ->
        // leads to permanent failure.
        ActivateSelf( KErrNotSupported );
        }
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::CancelConnection
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::CancelConnection()
    {
    LOG_1( _L("CAOConnectionImpl::CancelConnection") );
    Cancel();
    LOG_2( _L("CAOConnectionImpl::CancelConnection: Cur. state: %d"),
        iState );
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::IsConnectedToDefaultIAP
// ---------------------------------------------------------------------------
//
TBool CAOConnectionImpl::IsConnectedToDefaultIAP()
    {
    LOG_1( _L("CAOConnectionImpl::IsConnectedToDefaultIAP") );
    
    // Check if we have PDP context open to default IAP
    TBool connected = EFalse;
    TUint connectionCount = 0;
    TInt err = iConnection.EnumerateConnections( connectionCount );
    if ( err == KErrNone )
        {
        TPckgBuf<TConnectionInfoV2> connectionInfo;
        for ( TInt i = 0; i < connectionCount; i++ )
            {
            err = iConnection.GetConnectionInfo( i + 1, connectionInfo );
            if ( err == KErrNone )
                {
                if ( connectionInfo().iIapId == iSettings.AccessPointId() )
                    {
                    LOG_1( _L("CAOConnectionImpl::IsConnectedToDefaultIAP: \
                               Connected to default IAP") );
                    connected = ETrue;
                    break;
                    }
                }
            }
        }
        
    LOG_2( _L("CAOConnectionImpl::IsConnectedToDefaultIAP: Connected: %d "),
        connected );
        
    return connected;
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::NumberOfConnections
// ---------------------------------------------------------------------------
//
TInt CAOConnectionImpl::NumberOfConnections()
    {
    LOG_1( _L("CAOConnectionImpl::NumberOfConnections") );
    
    TUint connectionCount = 0;
    TInt err = iConnection.EnumerateConnections( connectionCount );
    if( err != KErrNone )
        {
        connectionCount = 0;
        }
    LOG_2( _L("> Number of connections: %d"), connectionCount );
        
    return static_cast<TInt>( connectionCount );
    }
    
// ---------------------------------------------------------------------------
// CAOConnectionImpl::CloseConnection
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::CloseConnection()
    {
    LOG_1( _L("CAOConnectionImpl::CloseConnection") );
    
    if ( iState == EListeningAccessPoint )
        {
        if ( IsActive() )
            {
            iConnection.CancelProgressNotification();	
            }
        	
    	iConnection.Close();
        
        // To really close: re-open
        TInt err = iConnection.Open( *iSocketServ );
        LOG_2( _L("> Re-opened connection handle: Err: %d"), err );

        ChangeState( EDisconnected );
        }
    }
        
// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
//
CAOConnectionImpl::CAOConnectionImpl(
                                      MAOConnectionObserver& aObserver,
                                      MAOSettings&           aSettings,
                                      RSocketServ*           aSocketServ ):
    CActive( CActive::EPriorityStandard ),
    iObserver( aObserver ),
    iSettings( aSettings ),
    iSocketServ( aSocketServ ),
    iState( EDisconnected )
    {
    LOG_1( _L("CAOConnectionImpl::CAOConnectionImpl") );
    
    CActiveScheduler::Add( this );
    }

// ---------------------------------------------------------------------------
// Symbian 2nd phase constructor
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::ConstructL()
    {
    LOG_1( _L("CAOConnectionImpl::ConstructL") );
    
    User::LeaveIfError( iConnection.Open( *iSocketServ, KAfInet ) );
    iCommsDatabase = CCommsDatabase::NewL( EDatabaseTypeUnspecified );
    
    iExtPrefs = new (ELeave) TExtendedConnPref;
    iPrefsList = TConnPrefList::NewL();
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::IsValidIAP
// ---------------------------------------------------------------------------
//
TBool CAOConnectionImpl::IsValidIAP( TUint32 aId ) const
    {
    LOG_1( _L("CAOConnectionImpl::IsValidIAP") );
    
    CCommsDbTableView* table = NULL;
    
    // E32USER Cbase panic 79 is raised if OpenViewMatchingUintLC does not
    // leave inside trap. Therefore pop table out from cleanup stack before
    // exiting from TRAP harness.
    TRAPD( error, table = iCommsDatabase->OpenViewMatchingUintLC(
        TPtrC( IAP ),
        TPtrC( COMMDB_ID ),
        aId );
        CleanupStack::Pop( table ) );
    
    if ( error == KErrNone )
        {
        error = table->GotoFirstRecord();
        }
    delete table;
    
    return error == KErrNone;
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::CompleteSelf
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::CompleteSelf( TRequestStatus& aStatus, TInt aReason )
    {
    LOG_1( _L("CAOConnectionImpl::CompleteSelf") );
    
    __ASSERT_DEBUG( IsActive(), Panic( ENotActive ) );
    __ASSERT_DEBUG( aStatus == KRequestPending, Panic( EReuqestNotPending ) );
    
    TRequestStatus* status = &aStatus;
    User::RequestComplete( status, aReason );
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::HandleOpeningLinkL
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::HandleOpeningLinkL( TInt aStatus )
    {
    LOG_1( _L("CAOConnectionImpl::HandleOpeningLinkL") );
    
    if ( aStatus == KErrNone )
        {
        // First check current status
        TInt err = iConnection.Progress( iProgressBuf() );
        if ( err == KErrNone && iProgressBuf().iError == KErrNone )
            {
            IssueProgressNotification();
            if ( iProgressBuf().iStage == KLinkLayerOpen )
                {
                // Link open
                ChangeState( EListeningAccessPoint );
                iObserver.HandlePDPContextActivatedL();
                }
            }
        else
            {
            BrodcastActivationFailedError( err );
            }
        }
    else
        {
        BrodcastActivationFailedError( aStatus );
        }
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::HandleListeningAccessPointL
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::HandleListeningAccessPointL( TInt aStatus )
    {
    LOG_1( _L("CAOConnectionImpl::HandleListeningAccessPointL") );
    LOG_2( _L("> aStatus: %d"), aStatus );
    LOG_2( _L("> iProgressBuf().iError: %d"), iProgressBuf().iError );
    
    if ( aStatus == KErrNone && iProgressBuf().iError == KErrNone )
        {
        // Check connection status
        switch ( iProgressBuf().iStage )
            {
            case KLinkLayerClosed:
                {
                LOG_1( _L("> Link closed") );
                
                // Connection disconnected
                // Stop connection just in case
                StopConnection();
                
                // Notify and change state
                BrodcastDisconnectedError( KErrDisconnected );
                break;
                }
            case KLinkLayerOpen:
                {
                LOG_1( _L("> Link open") );
                
                // everything ok -> continue listening
                IssueProgressNotification();
                break;
                }
            case KDataTransferTemporarilyBlocked:
                {
                LOG_1( _L("> Link temporarily blocked") );
                
                // Data transfer temporarily blocked
                // Continue listening and notify
                IssueProgressNotification();
                iObserver.HandlePDPContextTemporarilyBlockedL();
                break;
                }
            case KConnectionClosed:
                {
                LOG_1( _L("> Connection closed") );
                    
                // Notify and change state
                BrodcastDisconnectedError( KErrDisconnected );
                break;
                }                
            default:
                {
                LOG_2( _L("iProgressBuf().iStage: %d"),
                        iProgressBuf().iStage );
                
                // Just continue listening
                IssueProgressNotification();
                break;
                }
            }
        }
    else
        {
        // Handle error
        BrodcastDisconnectedError( aStatus );
        }
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::ChangeState
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::ChangeState( TInternalState aNewState )
    {
#ifdef LOGGING_ENABLED
    TInternalState old = iState;
    iState = aNewState;
    LOG_3( _L("CAOConnectionImpl::ChangeState >> Changing state %d -> %d"),
        old, iState );
#else
    iState = aNewState;
#endif // LOGGING_ENABLED
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::IssueProgressNotification
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::IssueProgressNotification()
    {
    LOG_1( _L("CAOConnectionImpl::IssueProgressNotification") );
    
    __ASSERT_DEBUG( !IsActive(), Panic( EConnectionAlreadyActive ) );
    
    iConnection.ProgressNotification( iProgressBuf, iStatus );
    SetActive();
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::BrodcastDisconnectedError
// ---------------------------------------------------------------------------
//
#ifdef LOGGING_ENABLED
void CAOConnectionImpl::BrodcastDisconnectedError( TInt aError )
#else
void CAOConnectionImpl::BrodcastDisconnectedError( TInt /*aError*/ )
#endif
    {
    LOG_2( _L("CAOConnectionImpl::BrodcastDisconnectedError: aError: %d"),
           aError );
    
    ChangeState( EDisconnected );
    TRAP_IGNORE( iObserver.HandlePDPContextDisconnectedL(
        MAOConnectionManager::EDisconnected ) );
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::BrodcastActivationFailedError
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::BrodcastActivationFailedError( TInt aError )
    {
    LOG_2( _L("CAOConnectionImpl::BrodcastActivationFailedError: aError: %d"),
        aError );
    
    ChangeState( EDisconnected );
    TRAP_IGNORE( iObserver.HandlePDPContextActivationFailedL(
        FailureReason( aError ) ) );
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::FailureReason
// ---------------------------------------------------------------------------
//
MAOConnectionManager::TFailureReason CAOConnectionImpl::FailureReason(
    TInt aError )
    {
    LOG_2( _L("CAOConnectionImpl::FailureReason: aError: %d"), aError );
    
    // Determine error cause
    MAOConnectionManager::TFailureReason reason =
        MAOConnectionManager::EPermanent;
    switch ( aError )
        {
        // Temporary cause
        case KErrGprsUserAuthenticationFailure:
        case KErrGprsActivationRejectedByGGSN:
        case KErrGprsActivationRejected:
        case KErrGprsServiceOptionTemporarilyOutOfOrder:
        case KErrConnectionTerminated:
            {
            LOG_1( _L("> Temporary failure") );
            reason = MAOConnectionManager::ETemporary;
            break;
            }
        // Permanent cause
        default:
            {
            LOG_1( _L("> Permanent failure") );
            reason = MAOConnectionManager::EPermanent;
            break;
            }
        }
        
    LOG_2( _L("CAOConnectionImpl::FailureReason: Reason: %d"), reason );
            
    return reason;
    }
    
// ---------------------------------------------------------------------------
// CAOConnectionImpl::ActivateSelf
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::ActivateSelf( TInt aReason )
    {
    LOG_2( _L("CAOConnectionImpl::ActivateSelf: aReason: %d"), aReason );
    
    __ASSERT_DEBUG( !IsActive(), Panic( EAlreadyActive ) );
    
    iStatus = KRequestPending;
    SetActive();
    CompleteSelf( iStatus, aReason );
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::StopConnection
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::StopConnection()
    {
    LOG_1( _L("CAOConnectionImpl::StopConnection") );
    
    TInt err = iConnection.Stop( RConnection::EStopAuthoritative );
    LOG_2( _L("> Stopped connection: Err: %d"), err );
    
    iConnection.Close();
    LOG_1( _L("> Closed connection handle") );
    
    err = iConnection.Open( *iSocketServ );
    LOG_2( _L("> Re-opened connection handle: Err: %d"), err );
    }



// ---------------------------------------------------------------------------
// CAOConnectionImpl::RunL
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::RunL()
    {
    LOG_2( _L("CAOConnectionImpl::RunL: iStatus: %d"), iStatus.Int() );
    
    TInt status = iStatus.Int();
    switch ( iState )
        {
        case EDisconnected:
            {
            // nothing to do
            break;
            }
        case EOpeningLink:
            {
            HandleOpeningLinkL( status );
            break;
            }
        case EListeningAccessPoint:
            {
            HandleListeningAccessPointL( status );
            break;
            }
        default:
            {
            LOG_1( _L("CAOConnectionImpl::RunL >> Invalid state!") );
            Panic( EInvalidState );
            break;
            }
        }
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::DoCancel
// ---------------------------------------------------------------------------
//
void CAOConnectionImpl::DoCancel()
    {
    LOG_1( _L("CAOConnectionImpl::DoCancel") );
    
    TInternalState currentState = iState;
    ChangeState( EDisconnected );
    switch ( currentState )
        {
        case EDisconnected:
            {
            // Nothing to do
            break;
            }
        case EOpeningLink:
        case EListeningAccessPoint:
            {
            // Ignore error code since there is nothing that can be done if
            // these fail
            iConnection.CancelProgressNotification();
            StopConnection();
            break;
            }
        default:
            {
            LOG_1( _L("CAOConnectionImpl::DoCancel >> Invalid state!") );
            Panic( EInvalidState );
            break;
            }
        }
    }

// ---------------------------------------------------------------------------
// CAOConnectionImpl::RunError
// ---------------------------------------------------------------------------
//
TInt CAOConnectionImpl::RunError( TInt aError )
    {
    LOG_2( _L("CAOConnectionImpl::RunError: aError: %d"), aError );
    
    switch ( iState )
        {
        case EDisconnected:
        case EOpeningLink:
        case EListeningAccessPoint:
            {
            BrodcastDisconnectedError( aError );
            break;
            }
        default:
            {
            LOG_1( _L("CAOConnectionImpl::RunError >> Invalid state!") );
            Panic( EInvalidState );
            break;
            }
        }
    ChangeState( EDisconnected );
    
    return KErrNone;
    }