diff -r 000000000000 -r 1bce908db942 natfw/natfwicecandidatehandler/src/cicecheckhandler.cpp --- /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& aPeerSelectedPairs ) + { + __ICEDP( "CIceCheckHandler::UpdateIceProcessingL, PEERSELECTEDCANDS" ) + __ASSERT_DEBUG( 0 != aPeerSelectedPairs.Count(), + User::Leave( KErrArgument ) ); + + RPointerArray 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& aRemoteCands ) + { + __ICEDP( "CIceCheckHandler::UpdateIceProcessingL, REMOTECANDS" ) + __ASSERT_DEBUG( 0 != aRemoteCands.Count(), User::Leave( KErrArgument ) ); + + RPointerArray 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& 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& 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 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 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 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& 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(); + }