natfw/natfwicecandidatehandler/src/cicecheckhandler.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwicecandidatehandler/src/cicecheckhandler.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,660 @@
+/*
+* Copyright (c) 2007 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 "natfwcandidate.h"
+#include "natfwcandidatepair.h"
+#include "mnatfwpluginobserver.h"
+#include "natfwcredentials.h"
+#include "cicecheckhandler.h"
+#include "cicesessiondata.h"
+#include "cicechecklist.h"
+#include "ciceconnectivitycheck.h"
+#include "natfwstunsrvclientsession.h"
+#include "icecandidatehandlerlogs.h"
+
+const TInt KMsToUsFactor = 1000;
+
+// ======== MEMBER FUNCTIONS ========
+
+CIceCheckHandler::CIceCheckHandler(
+        CIceSessionData& aSessionData,
+        MNcmConnectionMultiplexer& aMultiplexer,
+        CIceConnectionHandler& aConnHandler,
+        MIceNatPluginEventObs& aEventObserver )
+    :
+    iSessionData( aSessionData ),
+    iMultiplexer( aMultiplexer ),
+    iConnHandler( aConnHandler ),
+    iEventObserver( aEventObserver )
+    {
+    }
+
+
+void CIceCheckHandler::ConstructL()
+    {
+    iStunSrv = CNATFWSTUNSrvClientSession::NewL( *this, iMultiplexer );
+    }
+
+
+CIceCheckHandler* CIceCheckHandler::NewL(
+        CIceSessionData& aSessionData,
+        MNcmConnectionMultiplexer& aMultiplexer,
+        CIceConnectionHandler& aConnHandler,
+        MIceNatPluginEventObs& aEventObserver )
+    {
+    CIceCheckHandler* self 
+        = CIceCheckHandler::NewLC( 
+        aSessionData, aMultiplexer, aConnHandler, aEventObserver );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+CIceCheckHandler* CIceCheckHandler::NewLC(
+        CIceSessionData& aSessionData,
+        MNcmConnectionMultiplexer& aMultiplexer,
+        CIceConnectionHandler& aConnHandler,
+        MIceNatPluginEventObs& aEventObserver )
+    {
+    CIceCheckHandler* self 
+        = new( ELeave ) CIceCheckHandler( 
+        aSessionData, aMultiplexer, aConnHandler, aEventObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+
+CIceCheckHandler::~CIceCheckHandler()
+    {
+    iCheckLists.ResetAndDestroy();
+    delete iStunSrv;
+    iCurCredentials.ResetAndDestroy();
+    iBufferedChecks.Close();
+    }
+
+
+// Non-derived function
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::SetCredentialsL
+// Local credentials are needed for incoming request authentication and
+// must be set before starting connectivity checks.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::SetCredentialsL( 
+        const CNATFWCredentials& aCredentials )
+    {
+    if ( CNATFWCredentials::EInbound == aCredentials.Direction() )
+        {
+        UpdateStunServerParamsL();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::PerformConnectivityChecksL
+// Start perform connectivity checks.
+// Timer value depends on number of active check lists (initially one).
+// As an optimization ICE starts with one active check list and continue
+// with activation of other lists when certain results are got from first
+// check list.
+// Order of media streams is concluded from the order in which fetchcandidates
+// has been called.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::PerformConnectivityChecksL()
+    {
+    __ICEDP( "CIceCheckHandler::PerformConnectivityChecksL" )
+    __ASSERT_ALWAYS( iSessionData.Role(), User::Leave( KErrNotReady ) );
+    
+    if ( !iState )
+        {
+        FormChecklistsL();
+        UpdateStunServerParamsL();
+        
+        // Activate first check list
+        TTimeIntervalMicroSeconds32 interval 
+            = iSessionData.TaTimerValue() * KMsToUsFactor
+            * ( NumOfActiveCheckLists() + 1 );
+        iCheckLists[0]->InitializeCheckListL();
+        iCheckLists[0]->StartPerformChecksL( interval );
+        
+        SetState( EIceRunning );
+        ExecuteBufferedTriggeredChecksL();
+        }
+    else
+        {
+        // Either new collection is added or ICE is restarted for some stream
+        HandleNewCollectionsL();
+        HandleIceRestartsL();
+        UpdateStunServerParamsL();
+        
+        SetState( EIceRunning );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::UpdateIceProcessingL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::UpdateIceProcessingL( 
+        RPointerArray<CNATFWCandidatePair>& aPeerSelectedPairs )
+    {
+    __ICEDP( "CIceCheckHandler::UpdateIceProcessingL, PEERSELECTEDCANDS" )
+    __ASSERT_DEBUG( 0 != aPeerSelectedPairs.Count(), 
+        User::Leave( KErrArgument ) );
+    
+    RPointerArray<CIceCheckList> updatedLists;
+    CleanupClosePushL( updatedLists );
+    
+    // Find and update affected check lists
+    TInt selectedPairCount( aPeerSelectedPairs.Count() );
+    for ( TInt i( 0 ); i < selectedPairCount; ++i )
+        {
+        TUint streamCollId( 
+            aPeerSelectedPairs[i]->LocalCandidate().StreamCollectionId() );
+        CIceCheckList* checkList = ChecklistByCollectionIdL( streamCollId );
+        if ( KErrNotFound == updatedLists.Find( checkList )
+            && CIceCheckList::EIceCheckListRunning == checkList->State() )
+            {
+            // Checklist ignores candidates for the other collections
+            checkList->UpdateCheckListL( aPeerSelectedPairs );
+            updatedLists.AppendL( checkList );
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( &updatedLists );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::UpdateIceProcessingL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::UpdateIceProcessingL( 
+        RPointerArray<CNATFWCandidate>& aRemoteCands )
+    {
+    __ICEDP( "CIceCheckHandler::UpdateIceProcessingL, REMOTECANDS" )
+    __ASSERT_DEBUG( 0 != aRemoteCands.Count(), User::Leave( KErrArgument ) );
+    
+    RPointerArray<CIceCheckList> updatedLists;
+    CleanupClosePushL( updatedLists );
+    
+    // Find and update affected check lists
+    TInt remoteCandsCount( aRemoteCands.Count() );
+    for ( TInt i( 0 ); i < remoteCandsCount; ++i )
+        {
+        TUint streamCollId( aRemoteCands[i]->StreamCollectionId() );
+        CIceCheckList* checkList = ChecklistByCollectionIdL( streamCollId );
+        if ( KErrNotFound == updatedLists.Find( checkList )
+            && CIceCheckList::EIceCheckListRunning == checkList->State() )
+            {
+            // Checklist ignores candidates for the other collections
+            checkList->UpdateCheckListL( aRemoteCands );
+            updatedLists.AppendL( checkList );
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( &updatedLists );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::CleanupCollectionData
+// Session data must be updated before coming here.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::CleanupCollectionData( TUint aCollectionId )
+    {
+    __ICEDP( "CIceCheckHandler::CleanupCollectionData" )
+    
+    if ( EIceRunning == iState || EIceCompleted == iState )
+        {
+        CIceCheckList* checkList = ChecklistByCollectionId( aCollectionId );
+        if ( checkList )
+            {
+            TInt ind( iCheckLists.Find( checkList ) );
+            delete iCheckLists[ind];
+            iCheckLists.Remove( ind );
+            }
+        
+        TRAP_IGNORE( UpdateStunServerParamsL() )
+        }
+    }
+
+// Derived function
+
+// ---------------------------------------------------------------------------
+// From class MNATFWStunSrvObserver.
+// Entity which first receives incoming message must set aPeerAddr either to
+// the same as aFromAddr or to REMOTE-ADDR from data indication.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::STUNRequestReceivedL( const TInetAddr& aLocalAddr,
+        const TInetAddr& aFromAddr, const TInetAddr& aPeerAddr,
+        TUint aPriority, TBool aRemoteFavored )
+    {
+    if ( EIceRunning == iState || EIceCompleted == iState )
+        {
+        __ICEDP_INT1( "CIceCheckHandler::STUNRequestReceivedL, FAVORED:",
+            aRemoteFavored )
+        
+        const CNATFWCandidate* hostCand
+            = iSessionData.FindLocalCandidate( aLocalAddr );
+        __ASSERT_ALWAYS( NULL != hostCand, User::Leave( KErrNotFound ) );
+        
+        CIceCheckList* checkList 
+            = ChecklistByCollectionIdL( hostCand->StreamCollectionId() );
+        
+        checkList->STUNRequestReceivedL( 
+            aLocalAddr, aFromAddr, aPeerAddr, aPriority, aRemoteFavored );
+        }
+    else
+        {
+        __ICEDP( "CIceCheckHandler::STUNRequestReceivedL, BUFFERING" )
+        
+        // Must buffer triggered checks until remote credentials are known
+        TIceTriggeredCheckInfo check( aLocalAddr, aFromAddr, aPeerAddr,
+            aPriority, aRemoteFavored );
+        iBufferedChecks.AppendL( check );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::RoleChangeNeeded
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::RoleChangeNeeded( TNATFWIceRole aDesiredRole )
+    {
+    __ICEDP( "CIceCheckHandler::RoleChangeNeeded" )
+    
+    TNATFWIceRole currentRole = iSessionData.Role();
+    if ( currentRole != aDesiredRole )
+        {
+        iSessionData.SetRole( aDesiredRole );
+        
+        // pair priorities must be recomputed (ICE-17, section 7.2.1.1.)
+        TInt numOfCheckLists( iCheckLists.Count() );
+        for ( TInt i( 0 ); i < numOfCheckLists; ++i )
+            {
+            iCheckLists[i]->RecomputePairPriorities();
+            }
+        }
+    else
+        {
+        __ICEDP( "CIceCheckHandler::RoleChangeNeeded, ALREADY CHANGED" )
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::ChecklistCompletedL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::ChecklistCompletedL( 
+        const CIceCheckList& aCheckList,
+        const RPointerArray<CNATFWCandidatePair>& aSelectedPairs )
+    {
+    __ICEDP( "CIceCheckHandler::ChecklistCompletedL, SUCCESS" )
+    
+    TInt numOfSelectedPairs( aSelectedPairs.Count() );
+    __ASSERT_DEBUG( numOfSelectedPairs, User::Leave( KErrArgument ) );
+    
+    UpdateICEProcessingStateL( aCheckList );
+    for ( TInt i( 0 ); i < numOfSelectedPairs; ++i )
+        {
+        TUint streamId( aSelectedPairs[i]->LocalCandidate().StreamId() );
+        iEventObserver.PluginEventOccured( NULL, streamId,
+            MIceNatPluginEventObs::ECandidatePairFound,
+            KErrNone, aSelectedPairs[i] );
+        
+        iEventObserver.PluginEventOccured( NULL, streamId,
+            MIceNatPluginEventObs::EConnChecksCompleted,
+            KErrNone, NULL );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::ChecklistCompletedL
+// Check list has failed, post error events for the components.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::ChecklistCompletedL( 
+        const CIceCheckList& aCheckList,
+        const RArray<TUint>& aFailedComps,
+        TInt aErrCode )
+    {
+    __ICEDP( "CIceCheckHandler::ChecklistCompletedL, FAIL" )
+    
+    TInt numOfFailedComps( aFailedComps.Count() );
+    __ASSERT_DEBUG( numOfFailedComps, User::Leave( KErrArgument ) );
+    
+    UpdateICEProcessingStateL( aCheckList );
+    for ( TInt i( 0 ); i < numOfFailedComps; ++i )
+        {
+        iEventObserver.PluginEventOccured( NULL, aFailedComps[i],
+            MIceNatPluginEventObs::EConnChecksCompleted,
+            aErrCode, NULL );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::UpdateICEProcessingStateL
+// Update ICE processing state.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::UpdateICEProcessingStateL( 
+        const CIceCheckList& aCheckList )
+    {
+    __ICEDP( "CIceCheckHandler::UpdateICEProcessingStateL" )
+    
+    TBool processingCompleted( ETrue );
+    TInt numOfCheckLists( iCheckLists.Count() );
+    
+    for ( TInt i( 0 ); i < numOfCheckLists; ++i )
+        {
+        if ( CIceCheckList::EIceCheckListCompleted != iCheckLists[i]->State()
+            && CIceCheckList::EIceCheckListFailed != iCheckLists[i]->State() )
+            {
+            processingCompleted = EFalse;
+            }
+        }
+    
+    if ( processingCompleted )
+        {
+        SetState( EIceCompleted );
+        }
+    else
+        {
+        // ICE-15, 7.1.2.3.  Check List and Timer State Updates
+        UnFreezeCheckListsL( aCheckList, KNullDesC8 );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::UnFreezeCheckListsL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::UnFreezeCheckListsL(
+        const CIceCheckList& aExcludedList, const TDesC8& aFoundation )
+    {
+    __ICEDP( "CIceCheckHandler::UnFreezeCheckListsL" )
+    
+    TInt count( iCheckLists.Count() );
+    for ( TInt i( 0 ); i < count; ++i )
+        {
+        // Do not update same checklist which reported event
+        if ( iCheckLists[i] != &aExcludedList )
+            {
+            aFoundation.Length()
+                ? iCheckLists[i]->InitializeCheckListL( aFoundation )
+                : iCheckLists[i]->InitializeCheckListL();
+            
+            iCheckLists[i]->StartPerformChecksL( 
+                TTimeIntervalMicroSeconds32( 
+                    iSessionData.TaTimerValue() * KMsToUsFactor
+                    * ( NumOfActiveCheckLists() + 1 ) ) );
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::ComponentsHaveValidPairsL
+// ICE 7.1.2, Change state of first check in other check lists
+// to waiting if it is in frozen state and foundation is the same.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::ComponentsHaveValidPairsL( 
+        const CIceCheckList& aCheckList, const TDesC8& aFoundation )
+    {
+    __ICEDP( "CIceCheckHandler::ComponentsHaveValidPairsL" )
+    
+    UnFreezeCheckListsL( aCheckList, aFoundation );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::FormChecklistsL
+// Checklists must be in the same order than media lines in SDP. This is 
+// guaranteed if client has called fetchcandidates in correct order.
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::FormChecklistsL()
+    {
+    __ICEDP( "CIceCheckHandler::FormChecklistsL" )
+    
+    RArray<TUint> streamCollIds;
+    CleanupClosePushL( streamCollIds );
+    iSessionData.GetStreamCollectionIdsL( streamCollIds );
+    __ASSERT_ALWAYS( streamCollIds.Count(), User::Leave( KErrNotReady ) );
+    
+    TInt numOfChecklists( streamCollIds.Count() );
+    for ( TInt i = 0; i < numOfChecklists; ++i )
+        {
+        CIceCheckList* checklist 
+            = CIceCheckList::NewLC( 
+            *this, streamCollIds[i],
+            iSessionData, iConnHandler );
+        iCheckLists.AppendL( checklist );
+        CleanupStack::Pop( checklist );
+        }
+    
+    CleanupStack::PopAndDestroy( &streamCollIds );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::ChecklistByCollectionId
+// ---------------------------------------------------------------------------
+//
+CIceCheckList* CIceCheckHandler::ChecklistByCollectionId( 
+        TUint aStreamCollId )
+    {
+    TInt count( iCheckLists.Count() );
+    for ( TInt i = 0; i < count; ++i )
+        {
+        if ( iCheckLists[i]->StreamCollectionId() == aStreamCollId )
+            {
+            return iCheckLists[i];
+            }
+        }
+    
+    return NULL;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::ChecklistByCollectionIdL
+// ---------------------------------------------------------------------------
+//
+CIceCheckList* CIceCheckHandler::ChecklistByCollectionIdL( 
+        TUint aStreamCollId )
+    {
+    CIceCheckList* checkList = ChecklistByCollectionId( aStreamCollId );
+    if ( !checkList )
+        {
+        User::Leave( KErrNotFound );
+        }
+    
+    return checkList;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::SetState
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::SetState( TIceProcessingState aState )
+    {
+    __ICEDP( "CIceCheckHandler::SetState" )
+    
+    iState = aState;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::HandleNewCollectionsL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::HandleNewCollectionsL()
+    {
+    __ICEDP( "CIceCheckHandler::HandleNewCollectionsL" )
+    
+    RArray<TUint> streamCollIds;
+    CleanupClosePushL( streamCollIds );
+    iSessionData.GetStreamCollectionIdsL( streamCollIds );
+    TInt numOfCollections( streamCollIds.Count() );
+    __ASSERT_ALWAYS( numOfCollections, User::Leave( KErrNotReady ) );
+    
+    for ( TInt i( 0 ); i < numOfCollections; ++i )
+        {
+        if ( NULL == ChecklistByCollectionId( streamCollIds[i] ) )
+            {
+            CIceCheckList* checklist 
+                = CIceCheckList::NewLC( 
+                *this, streamCollIds[i],
+                iSessionData, iConnHandler );
+            iCheckLists.AppendL( checklist );
+            CleanupStack::Pop( checklist );
+            
+            TTimeIntervalMicroSeconds32 interval = 
+                iSessionData.TaTimerValue() * KMsToUsFactor
+                * ( NumOfActiveCheckLists() + 1 );
+            checklist->InitializeCheckListL();
+            checklist->StartPerformChecksL( interval );
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( &streamCollIds );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::HandleIceRestartsL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::HandleIceRestartsL()
+    {
+    __ICEDP( "CIceCheckHandler::HandleIceRestartsL" )
+    
+    TInt numOfCurCredentials( iCurCredentials.Count() );
+    __ASSERT_DEBUG( numOfCurCredentials, User::Leave( KErrNotReady ) );
+    
+    RPointerArray<CIceCheckList> updatedLists;
+    CleanupClosePushL( updatedLists );
+    
+    for ( TInt i( 0 ); i < numOfCurCredentials; ++i )
+        {
+        CNATFWCredentials* entry = iCurCredentials[i];
+        const CNATFWCredentials* storedId = iSessionData.Credentials(
+            entry->StreamId(), entry->Direction() );
+        
+        if ( storedId && ( *storedId != *entry ) )
+            {
+            CIceCheckList* checkList = ChecklistByCollectionIdL( 
+                storedId->StreamCollectionId() );
+
+            if ( KErrNotFound == updatedLists.Find( checkList ) )
+                {
+                TTimeIntervalMicroSeconds32 interval 
+                    = iSessionData.TaTimerValue() * KMsToUsFactor
+                    * ( NumOfActiveCheckLists() + 1 );
+                
+                checkList->RestartCheckListL( interval );
+                updatedLists.AppendL( checkList );
+                }
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( &updatedLists );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::NumOfActiveCheckLists
+// ---------------------------------------------------------------------------
+//
+TInt CIceCheckHandler::NumOfActiveCheckLists()
+    {
+    TInt count( 0 );
+    TInt numOfChecklists( iCheckLists.Count() );
+    for ( TInt i( 0 ); i < numOfChecklists; ++i )
+        {
+        if ( CIceCheckList::EIceCheckListRunning == iCheckLists[i]->State() )
+            {
+            count++;
+            }
+        }
+    
+    return count;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::UpdateStunServerParamsL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::UpdateStunServerParamsL()
+    {
+    const RPointerArray<CNATFWCredentials>& credentials
+        = iSessionData.Credentials();
+    TInt count( credentials.Count() );
+    __ICEDP_INT1( "CIceCheckHandler::UpdateStunServerParamsL, IDENT_COUNT:",
+        count )
+    
+    iStunSrv->RemoveAuthenticationParamsL( iCurCredentials );
+    iCurCredentials.ResetAndDestroy();
+    for ( TInt i( 0 ); i < count; ++i )
+        {
+        CNATFWCredentials* credential 
+            = CNATFWCredentials::NewLC( *credentials[i] );
+        iCurCredentials.AppendL( credential );
+        CleanupStack::Pop( credential );
+        }
+    
+    iStunSrv->AddAuthenticationParamsL( iCurCredentials );
+    iStunSrv->SetRoleL( iSessionData.Role(), iSessionData.TieBreaker() );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceCheckHandler::ExecuteBufferedTriggeredChecksL
+// ---------------------------------------------------------------------------
+//
+void CIceCheckHandler::ExecuteBufferedTriggeredChecksL()
+    {
+    TInt count( iBufferedChecks.Count() );
+    for ( TInt i( 0 ); i < count; ++i )
+        {
+        TIceTriggeredCheckInfo& check( iBufferedChecks[i] );
+        STUNRequestReceivedL( check.LocalAddr(), check.FromAddr(), 
+            check.PeerAddr(), check.Priority(), check.IsRemoteFavored() );
+        }
+    
+    iBufferedChecks.Reset();
+    }