diff -r 000000000000 -r 1bce908db942 natfw/natfwicecandidatehandler/src/cicechecklist.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/natfw/natfwicecandidatehandler/src/cicechecklist.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,1525 @@ +/* +* 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 "cicechecklist.h" +#include "cicecheckprioritizer.h" +#include "cicecandidateprioritizer.h" +#include "ciceconnectivitycheck.h" +#include "cicesessiondata.h" +#include "micechecklistobserver.h" +#include "cicevalidlist.h" +#include "icecandidatehandlerdefs.h" +#include "icecandidatehandlerlogs.h" + +const TUint KComponentIdRtp = 1; + +// ======== MEMBER FUNCTIONS ======== + +CIceCheckList::CIceCheckList( + MIceChecklistObserver& aClient, + TUint aStreamCollectionId, + CIceSessionData& aSessionData, + CIceConnectionHandler& aConnHandler ) + : + iStreamCollectionId( aStreamCollectionId ), + iClient( aClient ), + iSessionData( aSessionData ), + iConnHandler( aConnHandler ) + { + } + + +void CIceCheckList::ConstructL() + { + iCheckPrioritizer = CIceCheckPrioritizer::NewL(); + iCandPrioritizer = CIceCandidatePrioritizer::NewL( + iSessionData.Domain() ); + iTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + iValidList = CIceValidList::NewL( iStreamCollectionId ); + GenerateCheckListL( iChecks ); + } + + +CIceCheckList* CIceCheckList::NewL( + MIceChecklistObserver& aClient, + TUint aStreamCollectionId, + CIceSessionData& aSessionData, + CIceConnectionHandler& aConnHandler ) + { + CIceCheckList* self + = CIceCheckList::NewLC( aClient, aStreamCollectionId, + aSessionData, aConnHandler ); + CleanupStack::Pop( self ); + return self; + } + + +CIceCheckList* CIceCheckList::NewLC( + MIceChecklistObserver& aClient, + TUint aStreamCollectionId, + CIceSessionData& aSessionData, + CIceConnectionHandler& aConnHandler ) + { + CIceCheckList* self + = new( ELeave ) CIceCheckList( + aClient, aStreamCollectionId, aSessionData, aConnHandler ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + + +CIceCheckList::~CIceCheckList() + { + __ICEDP( "CIceCheckList::~CIceCheckList" ) + + iChecks.ResetAndDestroy(); + iCheckQue.Close(); + delete iCheckPrioritizer; + delete iCandPrioritizer; + delete iTimer; + delete iValidList; + iComponentIds.Close(); + iSelectedPairs.ResetAndDestroy(); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::TimerFired +// --------------------------------------------------------------------------- +// +TInt CIceCheckList::TimerFired( TAny* aObject ) + { + if ( aObject ) + { + CIceCheckList* list = reinterpret_cast( aObject ); + TRAPD( error, list->OnTimerFiredL() ) + if ( error ) + { + __ICEDP_INT1( "CIceCheckList::TimerFired, ERR:", error ) + if ( KErrNoMemory == error ) + { + TRAP_IGNORE( list->SetStateL( EIceCheckListFailed ) ) + } + else + { + ASSERT( EFalse ); + } + } + + return 1; + } + else + { + __ICEDP( "CIceCheckList::TimerFired, ELSE" ) + ASSERT( EFalse ); + return 0; // lint #527 + } + } + + +// Non-derived function + +// --------------------------------------------------------------------------- +// CIceCheckList::State +// --------------------------------------------------------------------------- +// +CIceCheckList::TIceCheckListState CIceCheckList::State() const + { + return iState; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::StreamCollectionId() +// --------------------------------------------------------------------------- +// +TUint CIceCheckList::StreamCollectionId() const + { + return iStreamCollectionId; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::InitializeCheckListL() +// Used to initialize check list corresponding first SDP mediastream. +// ICE-17, section 5.7.4. +// --------------------------------------------------------------------------- +// +void CIceCheckList::InitializeCheckListL() + { + __ICEDP( "CIceCheckList::InitializeCheckListL" ) + __ASSERT_DEBUG( iChecks.Count(), User::Leave( KErrNotReady ) ); + + TUint lowestComponentId = LowestComponentId( iComponentIds ); + + CDesC8ArrayFlat* foundations + = FoundationsForCollectionL( iStreamCollectionId ); + + TInt foundationCount( foundations->Count() ); + for ( TInt i(0); i < foundationCount; ++i ) + { + // inside foundation group set lowest component id waiting + TInt checkIndex( iChecks.Count() ); + TBool checkInitialized( EFalse ); + + while ( ( checkIndex-- ) && ( !checkInitialized ) ) + { + CIceConnectivityCheck& check( *iChecks[checkIndex] ); + if ( check.CandidatePair().Foundation() + == foundations->MdcaPoint(i) + && check.ComponentId() == lowestComponentId ) + { + check.Initialize(); + checkInitialized = ETrue; + } + } + } + + delete foundations; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::InitializeCheckListL +// ICE-17, 7.1.2.2.3, Updating Pair States. +// --------------------------------------------------------------------------- +// +void CIceCheckList::InitializeCheckListL( const TDesC8& aFoundation ) + { + __ICEDP( "CIceCheckList::InitializeCheckListL" ) + __ASSERT_DEBUG( iChecks.Count(), User::Leave( KErrNotReady ) ); + + TBool initComplete( EFalse ); + TInt count( iChecks.Count() ); + for ( TInt i = 0; i < count; ++i ) + { + if ( CIceConnectivityCheck::EIceCheckFrozen == iChecks[i]->State() + && iChecks[i]->CandidatePair().Foundation() == aFoundation ) + { + iChecks[i]->Initialize(); + initComplete = ETrue; + } + } + + if ( !initComplete && CheckListFrozen() ) + { + InitializeCheckListL(); + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::StartPerformChecksL() +// --------------------------------------------------------------------------- +// +void CIceCheckList::StartPerformChecksL( + const TTimeIntervalMicroSeconds32& anInterval ) + { + __ICEDP( "CIceCheckList::StartPerformChecksL" ) + + iInterval = anInterval; + SetStateL( EIceCheckListRunning ); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::RestartCheckListL() +// --------------------------------------------------------------------------- +// +void CIceCheckList::RestartCheckListL( + const TTimeIntervalMicroSeconds32& anInterval ) + { + __ICEDP( "CIceCheckList::RestartCheckListL" ) + __ASSERT_ALWAYS( EIceCheckListCompleted == State(), + User::Leave( KErrNotReady ) ); + + iValidList->FlushValidList(); + iChecks.ResetAndDestroy(); + GenerateCheckListL( iChecks ); + + iInterval = anInterval; + SetStateL( EIceCheckListRunning ); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::UpdateCheckListL() +// Controlling peer has selected candidate pairs to be used. +// ICE-17, 9.2.2.3. Existing Media Streams and remote-candidates. +// --------------------------------------------------------------------------- +// +void CIceCheckList::UpdateCheckListL( + RPointerArray& aPeerSelectedPairs ) + { + __ICEDP( "CIceCheckList::UpdateIceProcessingL" ) + __ASSERT_DEBUG( EIceCheckListRunning == State(), + User::Leave( KErrNotReady ) ); + __ASSERT_ALWAYS( !iSelectedPairs.Count(), + User::Leave( KErrAlreadyExists ) ); + + TInt numOfSelectedComps( aPeerSelectedPairs.Count() ); + for ( TInt i( 0 ); i < numOfSelectedComps; ++i ) + { + CNATFWCandidatePair* pair + = CNATFWCandidatePair::NewLC( *aPeerSelectedPairs[i] ); + iSelectedPairs.AppendL( pair ); + CleanupStack::Pop( pair ); + } + + DoLosingPairProcessingL( iSelectedPairs ); + UpdateCheckListStateL(); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::UpdateCheckListL() +// Peer has added new remote candidates to the session negotiation. +// ICE-17, 9.3.1.4. ICE Continuing for Existing Media Stream. +// --------------------------------------------------------------------------- +// +void CIceCheckList::UpdateCheckListL( + RPointerArray& /*aRemoteCands*/ ) + { + __ICEDP( "CIceCheckList::UpdateIceProcessingL" ) + __ASSERT_DEBUG( EIceCheckListRunning == State(), + User::Leave( KErrNotReady ) ); + + RPointerArray newCheckList; + CleanupResetAndDestroyPushL( newCheckList ); + GenerateCheckListL( newCheckList ); + + // Add new checks to the checklist + for ( TInt i( newCheckList.Count() - 1 ); i >= 0; --i ) + { + CIceConnectivityCheck* newCheck( newCheckList[i] ); + + TInt ind = iChecks.Find( + newCheck, CIceConnectivityCheck::MatchAddresses ); + + // All new checks are in frozen state initially + if ( KErrNotFound == ind ) + { + iChecks.InsertInOrderL( newCheck, + CIceConnectivityCheck::ComparePriorities ); + newCheckList.Remove( i ); + } + } + + TBool rtpComponentFound( EFalse ); + TInt ind( iChecks.Count() - 1 ); + while( ( !rtpComponentFound ) && ( 0 <= ind ) ) + { + if ( KComponentIdRtp == iChecks[ind]->ComponentId() + && CIceConnectivityCheck::EIceCheckSucceed + == iChecks[ind]->State() ) + { + rtpComponentFound = ETrue; + InitializeCheckList( + iChecks[ind]->CandidatePair().Foundation(), + KComponentIdRtp ); + + if ( iValidList->HasPairForComponents( iComponentIds ) ) + { + // Start checks in other check lists for checks of same type + iClient.ComponentsHaveValidPairsL( + *this, iChecks[ind]->CandidatePair().Foundation() ); + } + } + + ind--; + } + + CleanupStack::PopAndDestroy( &newCheckList ); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::GenerateCheckListL() +// --------------------------------------------------------------------------- +// +void CIceCheckList::GenerateCheckListL( + RPointerArray& aCheckList ) + { + __ICEDP( "CIceCheckList::GenerateCheckListL" ) + + RPointerArray localCandidates; + RPointerArray remoteCandidates; + CleanupClosePushL( localCandidates ); + CleanupClosePushL( remoteCandidates ); + + iSessionData.GetLocalCandidates( + iStreamCollectionId, + localCandidates ); + + iSessionData.GetRemoteCandidatesL( + iStreamCollectionId, + remoteCandidates ); + + __ASSERT_ALWAYS( localCandidates.Count() && remoteCandidates.Count(), + User::Leave( KErrNotReady ) ); + + PairCandidatesL( aCheckList, localCandidates, remoteCandidates ); + CleanupStack::PopAndDestroy( &remoteCandidates ); + CleanupStack::PopAndDestroy( &localCandidates ); + + iCheckPrioritizer->PrioritizeChecks( aCheckList, iSessionData.Role() ); + aCheckList.Sort( CIceConnectivityCheck::ComparePriorities ); + PruneChecksL( aCheckList ); + +#ifdef _DEBUG + __ICEDP( "CIceCheckList::GenerateCheckListL, LIST AFTER PRUNING" ) + TInt count( aCheckList.Count() ); + for ( TInt i(0); i < count; ++i ) + { + __ICEDP_ADDRLOG( "LOCAL_ADDR", + aCheckList[i]->CandidatePair().LocalCandidate().TransportAddr() ) + + __ICEDP_ADDRLOG( "PEER_ADDR", + aCheckList[i]->CandidatePair().RemoteCandidate().TransportAddr() ) + } +#endif + + GetComponentIdsL( iComponentIds ); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::PairCandidatesL +// --------------------------------------------------------------------------- +// +void CIceCheckList::PairCandidatesL( + RPointerArray& aCheckList, + RPointerArray& aLocalCands, + RPointerArray& aRemoteCands ) + { + __ICEDP( "CIceCheckList::PairCandidatesL" ) + + CNATFWCandidate* lCand( NULL ); + CNATFWCandidate* rCand( NULL ); + + TInt lInd = aLocalCands.Count(); + while ( lInd-- ) + { + lCand = aLocalCands[lInd]; + + TInt rInd = aRemoteCands.Count(); + while ( rInd-- ) + { + rCand = aRemoteCands[rInd]; + + if ( CompatibleCandidates( *lCand, *rCand ) ) + { + CIceConnectivityCheck* check + = CIceConnectivityCheck::NewLC( *this, *lCand, *rCand, + iConnHandler, iSessionData ); + + aCheckList.AppendL( check ); + CleanupStack::Pop( check ); + } + } + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::CompatibleCandidates +// According to ICE-17, 5.7.1. and ICE-TCP-03, 4.1. +// --------------------------------------------------------------------------- +// +TBool CIceCheckList::CompatibleCandidates( + const CNATFWCandidate& aCand1, const CNATFWCandidate& aCand2 ) const + { + __ICEDP( "CIceCheckList::CompatibleCandidates" ) + + TUint protocol( aCand1.TransportProtocol() ); + if ( protocol != aCand2.TransportProtocol() + || aCand1.TransportAddr().Family() != aCand2.TransportAddr().Family() + || aCand1.ComponentId() != aCand2.ComponentId() ) + { + return EFalse; + } + + if ( KProtocolInetUdp == protocol ) + { + return ETrue; + } + else + { + // we have not TCP support yet + return EFalse; + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::PruneChecksL +// ICE-17, 5.7.3 Pruning the pairs. +// Procedures of ICE-TCP-03, 4.1. to be added. +// --------------------------------------------------------------------------- +// +void CIceCheckList::PruneChecksL( + RPointerArray& aChecks ) + { + __ICEDP_INT1( "CIceCheckList::PruneChecksL start, COUNT:", aChecks.Count() ) + + // Replace server reflexive local candidate of the check by corresponding + // base candidate. + ReplaceReflexiveCandidatesWithBaseL( aChecks ); + + // Remove redundant checks. + for ( TInt i( aChecks.Count() - 1 ); 0 <= i; --i ) + { + TInt matchInd = aChecks.Find( aChecks[i], + CIceConnectivityCheck::MatchAddresses ); + + if ( KErrNotFound != matchInd && matchInd != i ) + { + delete aChecks[i]; + aChecks.Remove( i ); + } + } + + __ICEDP_INT1( "CIceCheckList::PruneChecksL end, COUNT:", aChecks.Count() ) + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::ReplaceReflexiveCandidatesWithBaseL +// --------------------------------------------------------------------------- +// +void CIceCheckList::ReplaceReflexiveCandidatesWithBaseL( + RPointerArray& aChecks ) + { + for ( TInt i( aChecks.Count() - 1 ); i >= 0; --i ) + { + CNATFWCandidate& localCand = const_cast + ( aChecks[ i ]->CandidatePair().LocalCandidate() ); + + if ( CNATFWCandidate::EServerReflexive == localCand.Type() ) + { + TInt numOfChecks( aChecks.Count() ); + for ( TInt j( 0 ); j < numOfChecks; ++j ) + { + const CNATFWCandidate& baseCand + = aChecks[ j ]->CandidatePair().LocalCandidate(); + if ( CNATFWCandidate::EHost == baseCand.Type() + && TIceUtils::MatchAddresses( + localCand.Base(), baseCand.Base() ) ) + { + localCand.SetTransportAddrL( baseCand.Base() ); + localCand.SetType( CNATFWCandidate::EHost ); + localCand.SetFoundationL( baseCand.Foundation() ); + localCand.SetPriority( baseCand.Priority() ); + } + } + } + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::OnTimerFiredL +// If triggered check queue contains items, top-most triggered check is sent. +// Otherwise an ordinary check is sent. ICE-17, 5.8. Scheduling checks. +// --------------------------------------------------------------------------- +// +void CIceCheckList::OnTimerFiredL() + { + __ICEDP( "CIceCheckList::OnTimerFiredL" ) + + TBool found = DequeueCheckL(); + if ( found ) + { + return; + } + + // Find highest priority check in waiting state + TInt ind = FindCheckInState( CIceConnectivityCheck::EIceCheckWaiting ); + if ( KErrNotFound != ind ) + { + TUint priority = PriorityForPeerReflCandL( + iChecks[ind]->CandidatePair().LocalCandidate() ); + iChecks[ind]->PerformConnCheckL( + CIceConnectivityCheck::EIceCheckTypePeriodic, priority, + RetransmissionTimeOut() ); + + return; + } + + ind = FindCheckInState( CIceConnectivityCheck::EIceCheckFrozen ); + if ( KErrNotFound != ind ) + { + iChecks[ind]->Initialize(); + TUint priority = PriorityForPeerReflCandL( + iChecks[ind]->CandidatePair().LocalCandidate() ); + iChecks[ind]->PerformConnCheckL( + CIceConnectivityCheck::EIceCheckTypePeriodic, priority, + RetransmissionTimeOut() ); + + return; + } + + iTimer->Cancel(); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::PriorityForPeerReflCandL +// --------------------------------------------------------------------------- +// +TUint CIceCheckList::PriorityForPeerReflCandL( + const CNATFWCandidate& aLocalCandidate ) const + { + __ICEDP( "CIceCheckList::PriorityForTentativePeerReflCandL" ) + + CNATFWCandidate* candidate = CNATFWCandidate::NewLC( aLocalCandidate ); + candidate->SetType( CNATFWCandidate::EPeerReflexive ); + iCandPrioritizer->PrioritizeL( *candidate ); + TUint priority( candidate->Priority() ); + CleanupStack::PopAndDestroy( candidate ); + + return priority; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::STUNRequestReceivedL +// Resolve local and remote candidates and set up them for actual handler. +// --------------------------------------------------------------------------- +// +void CIceCheckList::STUNRequestReceivedL( const TInetAddr& aLocalAddr, + const TInetAddr& aFromAddr, const TInetAddr& aPeerAddr, + TUint aPriority, TBool aRemoteFavored ) + { + __ICEDP( "CIceCheckList::STUNRequestReceivedL" ) + if ( ( State() != EIceCheckListRunning ) + && ( State() != EIceCheckListCompleted ) ) + { + SetStateL( EIceCheckListRunning ); + } + + // Find real local candidate where request was sent to + const CNATFWCandidate* localCand = NULL; + TBool relayUsed = !TIceUtils::MatchAddresses( aFromAddr, aPeerAddr ); + if ( relayUsed ) + { + __ICEDP( "CIceCheckList::STUNRequestReceivedL, RELAY USED" ) + + // Find out media component type (RTP/RTCP) + localCand = iSessionData.FindLocalCandidate( aLocalAddr ); + TUint componentId = localCand->ComponentId(); + localCand = iSessionData.FindLocalCandidate( + iStreamCollectionId, componentId, CNATFWCandidate::ERelay ); + } + else + { + localCand = iSessionData.FindLocalCandidate( aLocalAddr ); + } + + __ASSERT_ALWAYS( NULL != localCand, User::Leave( KErrNotFound ) ); + + const CNATFWCandidate* remoteCand + = iSessionData.FindRemoteCandidate( aPeerAddr ); + CNATFWCandidate* newRemoteCand = NULL; + if ( remoteCand ) + { + newRemoteCand = CNATFWCandidate::NewLC( *remoteCand ); + } + else + { + // ICE-17, 7.2.1.3. Learning Peer Reflexive (remote) Candidates + newRemoteCand = CNATFWCandidate::NewLC(); + newRemoteCand->SetTransportAddrL( aPeerAddr ); + newRemoteCand->SetType( CNATFWCandidate::EPeerReflexive ); + newRemoteCand->SetStreamCollectionId( localCand->StreamCollectionId() ); + newRemoteCand->SetStreamId( localCand->StreamId() ); + newRemoteCand->SetComponentId( localCand->ComponentId() ); + newRemoteCand->SetPriority( aPriority ); + + CNATFWCandidate* peerReflCand + = CNATFWCandidate::NewLC( *newRemoteCand ); + // Session data generates arbitrary foundation + iSessionData.AddPeerReflexiveCandidateL( peerReflCand, ETrue ); + CleanupStack::Pop( peerReflCand ); + } + + CNATFWCandidatePair* pair = CNATFWCandidatePair::NewLC( + *localCand, *newRemoteCand ); + pair->SetSelected( aRemoteFavored ); + HandleTriggeredCheckL( *pair ); + + CleanupStack::PopAndDestroy( pair ); + CleanupStack::PopAndDestroy( newRemoteCand ); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::RelayUsedForSelectedPairL +// --------------------------------------------------------------------------- +// +TBool CIceCheckList::RelayUsedForSelectedPairL() const + { + __ICEDP( "CIceCheckList::RelayUsedForSelectedPairL" ) + + TInt numOfComponents( iComponentIds.Count() ); + __ASSERT_ALWAYS( numOfComponents, User::Leave( KErrNotReady ) ); + + TBool relayUseDetected( EFalse ); + for ( TInt i( 0 ); i < numOfComponents; ++i ) + { + const CNATFWCandidatePair* pair + = iValidList->SelectedPair( iComponentIds[i] ); + + if ( !relayUseDetected && pair + && CNATFWCandidate::ERelay == pair->LocalCandidate().Type() ) + { + relayUseDetected = ETrue; + } + } + + return relayUseDetected; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::RecomputePairPriorities +// --------------------------------------------------------------------------- +// +void CIceCheckList::RecomputePairPriorities() + { + __ICEDP( "CIceCheckList::RecomputePairPriorities" ) + + iCheckPrioritizer->PrioritizeChecks( iChecks, iSessionData.Role() ); + + iChecks.Sort( CIceConnectivityCheck::ComparePriorities ); + } + + +// Derived function + +// --------------------------------------------------------------------------- +// CIceCheckList::CheckCompletedL +// From class MIceConnCheckListener. +// Once a successful check has completed for the first component, the other +// components of the same type and local preference will get performed. +// --------------------------------------------------------------------------- +// +void CIceCheckList::CheckCompletedL( + TInt aCompletionCode, + const CIceConnectivityCheck& aCheck, + CNATFWCandidatePair* aValidatedPair ) + { + __ICEDP_INT1( "CIceCheckList::CheckCompletedL, COMPLETION_CODE:", + aCompletionCode ) + + CleanupStack::PushL( aValidatedPair ); + + if ( KErrNone == aCompletionCode ) + { + __ASSERT_DEBUG( aValidatedPair, User::Leave( KErrArgument ) ); + + // Priorities of local and remote candidates of validated pair must + // be calculated before coming here. + iCheckPrioritizer->PrioritizePair( + *aValidatedPair, iSessionData.Role() ); + iValidList->AddValidPairL( *aValidatedPair ); + + if ( CNATFWCandidate::EPeerReflexive + == aValidatedPair->LocalCandidate().Type() ) + { + iSessionData.AddPeerReflexiveCandidateL( + CNATFWCandidate::NewL( aValidatedPair->LocalCandidate() ), + EFalse ); + } + + // Unfreeze other checks having same foundation ICE-17, 7.1.2.2.3 + InitializeCheckListL( aCheck.CandidatePair().Foundation() ); + + TBool validPairsExistForComponents( + iValidList->HasPairForComponents( iComponentIds ) ); + if ( validPairsExistForComponents ) + { + // Start checks in other check lists for candidates of same type + iClient.ComponentsHaveValidPairsL( *this, + aCheck.CandidatePair().Foundation() ); + } + + if ( ( validPairsExistForComponents ) && + ( EIceRoleControlling == iSessionData.Role() ) && + ( !NominationExecuted() ) ) + { + // stopping criteria is minimal latency; nominate pairs when we + // have some valid pair for each component + NominateCandidatePairsL(); + } + } + else if ( KErrRoleConflict == aCompletionCode ) + { + // ICE-17, section 7.1.2.1. Failure cases. + // Candidate pair whose check has generated 487 role conflict is + // enqueued to the triggered check queue. + TUint priority = PriorityForPeerReflCandL( + aCheck.CandidatePair().LocalCandidate() ); + + EnqueueCheckL( const_cast( aCheck ), + CIceConnectivityCheck::EIceCheckTypeTriggered, + priority ); + + TNATFWIceRole currentRole = iSessionData.Role(); + TNATFWIceRole desiredRole = ( EIceRoleControlling == currentRole ) + ? EIceRoleControlled : EIceRoleControlling; + iClient.RoleChangeNeeded( desiredRole ); + } + else + { + // unrecoverable failure + } + + CleanupStack::PopAndDestroy( aValidatedPair ); + + DoLosingPairProcessingL( iSelectedPairs ); + + // ICE-17, 7.1.2.3. Check List and Timer State Updates + UpdateCheckListStateL(); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::NominationCompletedL +// From class MIceConnCheckListener. +// ICE-15, 7.1.2.2.4. Updating the Nominated Flag +// --------------------------------------------------------------------------- +// +void CIceCheckList::NominationCompletedL( + TInt aCompletionCode, + const CIceConnectivityCheck& /*aCheck*/, + const CNATFWCandidatePair& aValidatedPair ) + { + __ICEDP( "CIceCheckList::NominationCompletedL" ) + + if ( KErrNone == aCompletionCode ) + { + iValidList->SetPairNominatedL( aValidatedPair ); + } + + // ICE-17, 7.1.2.3. Check List and Timer State Updates + UpdateCheckListStateL(); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::HandleTriggeredCheckL +// ICE-17 7.2.1.4. Triggered Checks +// STUN server has set PRIORITY & USE-CANDIDATE -attributes to the remote +// candidate. +// --------------------------------------------------------------------------- +// +void CIceCheckList::HandleTriggeredCheckL( + const CNATFWCandidatePair& aPair ) + { + __ICEDP( "CIceCheckList::HandleTriggeredCheckL" ) + + TUint trCheckPriority + = PriorityForPeerReflCandL( aPair.LocalCandidate() ); + + TInt ind = FindCheck( aPair ); + + if ( KErrNotFound != ind ) + { + // We have corresponding check already in checklist + CIceConnectivityCheck& check = *iChecks[ind]; + check.SetRemoteCheckInfo( + aPair.RemoteCandidate().Priority(), + aPair.Selected() ); + + CIceConnectivityCheck::TIceCheckState state = check.State(); + if ( CIceConnectivityCheck::EIceCheckWaiting & state + || CIceConnectivityCheck::EIceCheckFrozen & state ) + { + EnqueueCheckL( check, + CIceConnectivityCheck::EIceCheckTypeTriggered, + trCheckPriority ); + } + else if ( CIceConnectivityCheck::EIceCheckInProgress & state ) + { + __ICEDP( "CIceCheckList::HandleTriggeredCheckL, INPROGRESS" ) + // Nomination check should always succeed, so do not cancel it. + // With ordinary checks ICE specification is followed. + if ( !check.Nominated() ) + { + check.Cancel(); + EnqueueCheckL( check, + CIceConnectivityCheck::EIceCheckTypeTriggered, + trCheckPriority ); + } + } + else if ( CIceConnectivityCheck::EIceCheckFailed & state ) + { + EnqueueCheckL( check, + CIceConnectivityCheck::EIceCheckTypeTriggered, + trCheckPriority ); + } + else if ( CIceConnectivityCheck::EIceCheckSucceed & state ) + { + if ( aPair.Selected() ) + { + // ICE-17, 7.2.1.5, Updating the Nominated Flag + const_cast + ( check.CandidatePair() ).SetSelected( ETrue ); + // Set validated pair learned from this check as selected + const CNATFWCandidatePair* validatedPair + = check.ValidatedPair(); + __ASSERT_DEBUG( NULL != validatedPair, + User::Leave( KErrNotReady ) ); + + iValidList->SetPairNominatedL( *validatedPair ); + + UpdateCheckListStateL(); + } + } + else + { + __ICEDP( "CIceCheckList::HandleTriggeredCheckL, ASSERT" ) + ASSERT( EFalse ); + } + } + else + { + // We have learned peer reflexive remote candidate + CIceConnectivityCheck* trCheck = CIceConnectivityCheck::NewLC( + *this, aPair.LocalCandidate(), aPair.RemoteCandidate(), + iConnHandler, iSessionData ); + iCheckPrioritizer->PrioritizeCheck( *trCheck, + iSessionData.Role() ); + iChecks.InsertInOrderL( trCheck, + CIceConnectivityCheck::ComparePriorities ); + CleanupStack::Pop( trCheck ); + + // remote priority used due to ICE-17, 7.1.2.2.2 + trCheck->SetRemoteCheckInfo( + aPair.RemoteCandidate().Priority(), aPair.Selected() ); + + EnqueueCheckL( *trCheck, + CIceConnectivityCheck::EIceCheckTypeTriggered, + trCheckPriority ); + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::UpdateCheckListStateL +// Check list state is updated due to check completion or pair nomination. +// Refer to ICE-17 7.1.2.3. Check List and Timer State Updates and +// ICE-15 8.2. Updating States. +// Change state to completed if controlling client has selected candidate +// pair for every component of the media stream. If all checks for any +// media component has failed, ICE processing is stopped for a media stream. +// --------------------------------------------------------------------------- +// +void CIceCheckList::UpdateCheckListStateL() + { + __ICEDP( "CIceCheckList::UpdateCheckListStateL" ) + + if ( EIceCheckListRunning == State() ) + { + TInt numOfComponents( iComponentIds.Count() ); + __ASSERT_DEBUG( numOfComponents, User::Leave( KErrNotReady ) ); + + for ( TInt i( 0 ); i < numOfComponents; ++i ) + { + // ICE-15, 8.2. If some component has completed, remove pending + // checks for that component. + RemovePendingChecks( iComponentIds[i] ); + } + + if ( iValidList->NominatedPairsExist( iComponentIds ) ) + { + // when check list completes, frozen check lists are unfreezed + SetStateL( EIceCheckListCompleted ); + } + else + { + // If all checks are completed and there is not valid pair for + // each media component, check list has failed. ICE-17, 7.1.2.3. + TInt activeStates = ( + CIceConnectivityCheck::EIceCheckWaiting | + CIceConnectivityCheck::EIceCheckInProgress | + CIceConnectivityCheck::EIceCheckFrozen ); + + if ( KErrNotFound == FindCheckInState( activeStates ) + && !iValidList->HasPairForComponents( iComponentIds ) ) + { + // when check list completes, frozen check lists are unfreezed + SetStateL( EIceCheckListFailed ); + } + } + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::RemovePendingChecks +// ICE-17, 8.1.2 Updating States +// --------------------------------------------------------------------------- +// +void CIceCheckList::RemovePendingChecks( TUint aComponentId ) + { + const CNATFWCandidatePair* nominatedPair + = iValidList->SelectedPair( aComponentId ); + if ( nominatedPair ) + { + TInt stateMask = ( + CIceConnectivityCheck::EIceCheckWaiting | + CIceConnectivityCheck::EIceCheckFrozen ); + + TInt ind = FindCheckInState( stateMask, aComponentId ); + while ( KErrNotFound != ind ) + { + iChecks.Remove( ind ); + ind = FindCheckInState( stateMask, aComponentId ); + } + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::GetComponentIdsL +// --------------------------------------------------------------------------- +// +void CIceCheckList::GetComponentIdsL( RArray& aComponentIds ) const + { + __ICEDP( "CIceCheckList::GetComponentIdsL" ) + + aComponentIds.Reset(); + TInt count( iChecks.Count() ); + for ( TInt i( 0 ); i < count; ++i ) + { + TUint curCompId + = iChecks[i]->CandidatePair().LocalCandidate().ComponentId(); + if ( KErrNotFound == aComponentIds.Find( curCompId ) ) + { + aComponentIds.AppendL( curCompId ); + } + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::FindCheckInState +// --------------------------------------------------------------------------- +// +TInt CIceCheckList::FindCheckInState( TInt aStateMask ) + { + TInt count( iChecks.Count() ); + __ICEDP_INT1( "CIceCheckList::FindCheckInState1:", count ) + + for ( TInt i( 0 ); i < count; ++i ) + { + CIceConnectivityCheck& check( *iChecks[i] ); + if ( aStateMask & check.State() ) + { + return i; + } + } + + return KErrNotFound; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::FindCheckInState +// --------------------------------------------------------------------------- +// +TInt CIceCheckList::FindCheckInState( TInt aStateMask, TUint aComponentId ) + { + TInt count( iChecks.Count() ); + for ( TInt i( 0 ); i < count; ++i ) + { + CIceConnectivityCheck& check( *iChecks[i] ); + if ( ( aStateMask & check.State() ) + && check.ComponentId() == aComponentId ) + { + return i; + } + } + + return KErrNotFound; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::FindCheckInState +// --------------------------------------------------------------------------- +// +TInt CIceCheckList::FindCheckInState( TInt aStateMask, + const TInetAddr& aRemoteAddr ) + { + TInt count( iChecks.Count() ); + for ( TInt i( 0 ); i < count; ++i ) + { + CIceConnectivityCheck& check( *iChecks[i] ); + const TInetAddr& remoteAddr + = check.CandidatePair().RemoteCandidate().TransportAddr(); + if ( ( aStateMask & check.State() ) + && TIceUtils::MatchAddresses( remoteAddr, aRemoteAddr ) ) + { + return i; + } + } + + return KErrNotFound; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::FindCheck +// --------------------------------------------------------------------------- +// +TInt CIceCheckList::FindCheck( const CNATFWCandidatePair& aPair ) + { + for ( TInt i( iChecks.Count() - 1 ); 0 <= i; --i ) + { + TBool match = CNATFWCandidatePair::MatchAddresses( + iChecks[i]->CandidatePair(), aPair ); + if ( match ) + { + return i; + } + } + + return KErrNotFound; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::SetStateL +// --------------------------------------------------------------------------- +// +void CIceCheckList::SetStateL( TIceCheckListState aNewState ) + { + __ICEDP( "CIceCheckList::SetStateL" ) + + __ASSERT_ALWAYS( iState != aNewState, User::Leave( KErrArgument ) ); + iState = aNewState; + iCheckQue.Reset(); + + if ( EIceCheckListCompleted == aNewState ) + { + iTimer->Cancel(); + iSelectedPairs.ResetAndDestroy(); + + TInt numOfComponents( iComponentIds.Count() ); + RPointerArray selectedPairs; + CleanupResetAndDestroyPushL( selectedPairs ); + for ( TInt i( 0 ); i < numOfComponents; ++i ) + { + CNATFWCandidatePair* newPair = CNATFWCandidatePair::NewLC( + *iValidList->SelectedPair( iComponentIds[i] ) ); + selectedPairs.AppendL( newPair ); + CleanupStack::Pop( newPair ); + } + + iClient.ChecklistCompletedL( *this, selectedPairs ); + + selectedPairs.Close(); + CleanupStack::Pop( &selectedPairs ); + } + else if ( EIceCheckListRunning == aNewState ) + { + if ( !iTimer->IsActive() ) + { + TCallBack callBack( CIceCheckList::TimerFired, this ); + iTimer->Start( 0, iInterval, callBack ); + } + } + else if ( EIceCheckListFailed == aNewState ) + { + iTimer->Cancel(); + iSelectedPairs.ResetAndDestroy(); + + RArray failedStreams; + CleanupClosePushL( failedStreams ); + TInt stateMask = ( + CIceConnectivityCheck::EIceCheckWaiting | + CIceConnectivityCheck::EIceCheckInProgress | + CIceConnectivityCheck::EIceCheckSucceed | + CIceConnectivityCheck::EIceCheckFailed | + CIceConnectivityCheck::EIceCheckFrozen ); + + TInt numOfComponents( iComponentIds.Count() ); + for ( TInt i( 0 ); i < numOfComponents; ++i ) + { + if ( KErrNotFound != FindCheckInState( + stateMask, iComponentIds[i] ) ) + { + failedStreams.AppendL( iChecks[i]->StreamId() ); + } + } + + iClient.ChecklistCompletedL( + *this, failedStreams, KErrCouldNotConnect ); + CleanupStack::PopAndDestroy( &failedStreams ); + } + else + { + __ICEDP( "CIceCheckList::SetStateL, ELSE" ) + User::Leave( KErrArgument ); + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::DoLosingPairProcessingL +// ICE-17, 9.2.2.3. +// ICE SHOULD be restarted if some peer selected pair has failed. +// --------------------------------------------------------------------------- +// +void CIceCheckList::DoLosingPairProcessingL( + const RPointerArray& aSelectedPairs ) + { + __ICEDP( "CIceCheckList::DoLosingPairProcessingL" ) + + // find out losing pairs + RPointerArray losingPairs; + CleanupResetAndDestroyPushL( losingPairs ); + for ( TInt i( aSelectedPairs.Count() - 1 ); 0 <= i ; --i ) + { + const CNATFWCandidatePair& pair( *aSelectedPairs[i] ); + if ( iValidList->HasPair( pair ) ) + { + iValidList->SetPairNominatedL( pair ); + } + else + { + CNATFWCandidatePair* losingPair + = CNATFWCandidatePair::NewLC( pair ); + losingPairs.AppendL( losingPair ); + CleanupStack::Pop( losingPair ); + } + } + + /* If none of peer selected pairs is in-progress and at least one + is failed, check list is completed unsuccessfully. If some selected + pair is in-progress, we wait for check completion and do this + processing again. */ + TBool inProgressCheckFound( EFalse ); + TBool failedCheckFound( EFalse ); + TInt losingPairInd( losingPairs.Count() - 1 ); + while ( ( 0 <= losingPairInd ) && ( !inProgressCheckFound ) ) + { + TInetAddr remoteAddr( + losingPairs[losingPairInd]->RemoteCandidate().TransportAddr() ); + + TInt inProgressCheckInd = FindCheckInState( + CIceConnectivityCheck::EIceCheckInProgress, remoteAddr ); + if ( KErrNotFound == inProgressCheckInd ) + { + TInt failedCheckInd = FindCheckInState( + CIceConnectivityCheck::EIceCheckFailed, remoteAddr ); + if ( KErrNotFound != failedCheckInd ) + { + failedCheckFound = ETrue; + } + } + else + { + inProgressCheckFound = ETrue; + } + + losingPairInd--; + } + + if ( failedCheckFound ) + { + SetStateL( EIceCheckListFailed ); + } + + CleanupStack::PopAndDestroy( &losingPairs ); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::NominateCandidatePairsL +// Resends connectivity checks to select pair for each media component. +// ICE-17, section 8.1.1.1, regular nomination is used. +// --------------------------------------------------------------------------- +// +void CIceCheckList::NominateCandidatePairsL() + { + __ICEDP( "CIceCheckList::NominateCandidatePairsL" ) + + TInt numOfComponents( iComponentIds.Count() ); + for ( TInt i( 0 ); i < numOfComponents; ++i ) + { + const CNATFWCandidatePair* pair + = iValidList->HighestPriorityPair( iComponentIds[i] ); + ASSERT( NULL != pair ); + const TInetAddr& lAddr( pair->LocalCandidate().TransportAddr() ); + const TInetAddr& rAddr( pair->RemoteCandidate().TransportAddr() ); + + TInt index( iChecks.Count() ); + TBool checkFound( EFalse ); + while ( !checkFound && --index >= 0 ) + { + const CNATFWCandidatePair* validatedPair + = iChecks[index]->ValidatedPair(); + if ( validatedPair ) + { + const TInetAddr& lAddrOfCheck + = validatedPair->LocalCandidate().TransportAddr(); + const TInetAddr& rAddrOfCheck + = validatedPair->RemoteCandidate().TransportAddr(); + + checkFound = + ( TIceUtils::MatchAddresses( lAddrOfCheck, lAddr ) && + TIceUtils::MatchAddresses( rAddrOfCheck, rAddr ) ); + } + } + + User::LeaveIfError( index ); + EnqueueCheckL( *iChecks[index], + CIceConnectivityCheck::EIceCheckTypeNomination, 0 ); + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::CheckListFrozen +// --------------------------------------------------------------------------- +// +TBool CIceCheckList::CheckListFrozen() + { + __ICEDP( "CIceCheckList::CheckListFrozen" ) + + TInt ind( iChecks.Count() ); + while ( ind-- ) + { + if ( CIceConnectivityCheck::EIceCheckFrozen != iChecks[ind]->State() ) + { + return EFalse; + } + } + + return ETrue; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::EnqueueCheckL +// --------------------------------------------------------------------------- +// +void CIceCheckList::EnqueueCheckL( CIceConnectivityCheck& aCheck, + CIceConnectivityCheck::TIceCheckType aType, + TUint aLocalPriority ) + { + TIceCheckQueItem item( aCheck, aType, aLocalPriority ); + + TInt index = iCheckQue.Find( item, TIceCheckQueItem::MatchCheck ); + if ( CIceConnectivityCheck::EIceCheckTypeNomination == aType + && KErrNotFound != index ) + { + // nomination check is privileged over triggered one + __ICEDP( "CIceCheckList::EnqueueCheckL, REMOVE TRIGGERED CHECK" ) + iCheckQue.Remove( index ); + } + + // do not allow duplicate entries + if ( KErrNotFound == iCheckQue.Find( + item, TIceCheckQueItem::MatchCheck ) ) + { + __ICEDP( "CIceCheckList::EnqueueCheckL, APPENDING" ) + iCheckQue.AppendL( item ); + + if ( !iTimer->IsActive() ) + { + TCallBack callBack( CIceCheckList::TimerFired, this ); + iTimer->Start( 0, iInterval, callBack ); + } + } + else + { + __ICEDP( "CIceCheckList::EnqueueCheckL, DUPLICATE ENTRY" ) + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::DequeueCheckL +// --------------------------------------------------------------------------- +// +TBool CIceCheckList::DequeueCheckL() + { + __ICEDP_INT1( "CIceCheckList::DequeueCheckL, COUNT:", iCheckQue.Count() ) + + if ( 0 != iCheckQue.Count() ) + { + TIceCheckQueItem item = iCheckQue[0]; + iCheckQue.Remove( 0 ); + + CIceConnectivityCheck& check = item.Check(); + if ( CIceConnectivityCheck::EIceCheckTypeNomination == item.Type() ) + { + check.PerformNominationL( RetransmissionTimeOut() ); + } + else + { + CIceConnectivityCheck::TIceCheckState state = check.State(); + // save bandwidth if previous transaction already succeeded + if ( CIceConnectivityCheck::EIceCheckSucceed != state ) + { + check.Initialize(); + check.PerformConnCheckL( + CIceConnectivityCheck::EIceCheckTypeTriggered, + item.Priority(), RetransmissionTimeOut() ); + } + } + + return ETrue; + } + else + { + return EFalse; + } + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::RetransmissionTimeOut +// ICE-17, section 16. RTO = MAX (100ms, Ta*N * (Num-Waiting)) +// --------------------------------------------------------------------------- +// +TUint CIceCheckList::RetransmissionTimeOut() const + { + TInt numOfWaitingPairs( 0 ); + + TInt numOfChecks( iChecks.Count() ); + for ( TInt i( 0 ); i < numOfChecks; ++i ) + { + CIceConnectivityCheck& check( *iChecks[i] ); + if ( CIceConnectivityCheck::EIceCheckWaiting == check.State() ) + { + numOfWaitingPairs++; + } + } + + const TInt KMinimumRto( 100 ); + return TUint( Max( KMinimumRto, iInterval.Int() * numOfWaitingPairs ) ); + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::FoundationsForCollectionL +// --------------------------------------------------------------------------- +// +CDesC8ArrayFlat* CIceCheckList::FoundationsForCollectionL( + TUint aStreamCollectionId ) const + { + const TInt KGranularity(4); + CDesC8ArrayFlat* descArray = new (ELeave) CDesC8ArrayFlat( KGranularity ); + CleanupStack::PushL( descArray ); + + TInt numOfChecks( iChecks.Count() ); + for ( TInt i(0); i < numOfChecks; ++i ) + { + CIceConnectivityCheck& check( *iChecks[i] ); + if ( check.StreamCollectionId() == aStreamCollectionId ) + { + TInt matchItemInd(0); + const TDesC8& foundation( + iChecks[i]->CandidatePair().Foundation() ); + if ( 0 != descArray->Find( foundation, matchItemInd ) ) + { + descArray->AppendL( foundation ); + } + } + } + + CleanupStack::Pop( descArray ); + return descArray; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::LowestComponentId +// --------------------------------------------------------------------------- +// +TUint CIceCheckList::LowestComponentId( RArray& aComponentIds ) const + { + TInt componentIdCount( aComponentIds.Count() ); + ASSERT( 0 != componentIdCount ); + + TUint lowestComponentId( aComponentIds[0] ); + for ( TInt i(1); i < componentIdCount; ++i ) + { + if ( aComponentIds[i] < lowestComponentId ) + { + lowestComponentId = aComponentIds[i]; + } + } + + return lowestComponentId; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::NominationExecuted +// --------------------------------------------------------------------------- +// +TBool CIceCheckList::NominationExecuted() const + { + TInt numOfChecks( iChecks.Count() ); + for ( TInt i(0); i < numOfChecks; ++i ) + { + CIceConnectivityCheck& check( *iChecks[i] ); + if ( check.Nominated() ) + { + return ETrue; + } + } + + return EFalse; + } + + +// --------------------------------------------------------------------------- +// CIceCheckList::InitializeCheckList +// Special initialization due to ICE-17, 9.3.1.4 ICE Continuing for Existing +// Media Stream. +// --------------------------------------------------------------------------- +// +void CIceCheckList::InitializeCheckList( const TDesC8& aFoundation, + TInt aExcludedComponentId ) + { + __ICEDP( "CIceCheckList::InitializeCheckList" ) + ASSERT( 0 != iChecks.Count() ); + + for ( TInt i( iChecks.Count() - 1 ); i >= 0; --i ) + { + if ( CIceConnectivityCheck::EIceCheckFrozen == iChecks[i]->State() + && iChecks[i]->CandidatePair().Foundation() == aFoundation + && iChecks[i]->ComponentId() != aExcludedComponentId ) + { + iChecks[i]->Initialize(); + } + } + }