natfw/natfwicecandidatehandler/src/cicelocalcandidatefinder.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwicecandidatehandler/src/cicelocalcandidatefinder.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,441 @@
+/*
+* Copyright (c) 2006-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 <ecom/ecom.h>
+#include "natfwpluginapi.h"
+#include "natfwcandidate.h"
+#include "cicelocalcandidatefinder.h"
+#include "cicesessiondata.h"
+#include "cicecandidateprioritizer.h"
+#include "ticenatplugincontaineriter.h"
+#include "icecandidatehandlerlogs.h"
+#include "cicehostresolver.h"
+
+const TInt KMsToUsFactor = 1000;
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::CIceLocalCandidateFinder
+// ---------------------------------------------------------------------------
+//
+CIceLocalCandidateFinder::CIceLocalCandidateFinder(
+        MIceNatPluginEventObs& aEventObserver,
+        CIceSessionData& aSessionData,
+        CIceNatPluginContainer& aPluginContainer )
+    :
+    iEventObserver( aEventObserver ),
+    iSessionData( aSessionData ),
+    iPluginContainer( aPluginContainer )
+    {
+    __ICEDP( "CIceLocalCandidateFinder::CIceLocalCandidateFinder" )
+    }
+    
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+void CIceLocalCandidateFinder::ConstructL()
+    {
+    __ICEDP( "CIceLocalCandidateFinder::ConstructL" )
+    
+    iPrioritizer = CIceCandidatePrioritizer::NewL( iSessionData.Domain() );
+    iTimer = CPeriodic::NewL( CActive::EPriorityStandard );
+    
+    iPluginContainer.RegObserverForEventL( *this, 
+        MIceNatPluginEventObs::ELocalCandidateFound );
+    iPluginContainer.RegObserverForEventL( *this, 
+        MIceNatPluginEventObs::EFetchingCompleted );
+    }
+    
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+CIceLocalCandidateFinder* CIceLocalCandidateFinder::NewL(
+        MIceNatPluginEventObs& aEventObserver,
+        CIceSessionData& aSessionData,
+        CIceNatPluginContainer& aPluginContainer )
+    {
+    __ICEDP( "CIceLocalCandidateFinder::NewL" )
+    
+    CIceLocalCandidateFinder* self = CIceLocalCandidateFinder::NewLC(
+        aEventObserver, aSessionData, aPluginContainer );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+CIceLocalCandidateFinder* CIceLocalCandidateFinder::NewLC(
+        MIceNatPluginEventObs& aEventObserver,
+        CIceSessionData& aSessionData,
+        CIceNatPluginContainer& aPluginContainer )
+    {
+    __ICEDP( "CIceLocalCandidateFinder::NewLC" )
+
+    CIceLocalCandidateFinder* self = new( ELeave ) 
+        CIceLocalCandidateFinder( 
+        aEventObserver, aSessionData, aPluginContainer );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// destructor
+// ---------------------------------------------------------------------------
+//
+CIceLocalCandidateFinder::~CIceLocalCandidateFinder()
+    {
+    __ICEDP( "CIceLocalCandidateFinder::~CIceLocalCandidateFinder" )
+    
+    delete iPrioritizer;
+    delete iTimer;
+    iResolveRequests.Close();
+    iResolvingCnts.Close();
+    
+    iPluginContainer.UnregObserver( *this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::ResolveNextCandidate
+// ---------------------------------------------------------------------------
+//
+TInt CIceLocalCandidateFinder::ResolveNextCandidate( TAny* aObject )
+    {
+    if ( aObject )
+        {
+        TRAP_IGNORE( 
+            reinterpret_cast<CIceLocalCandidateFinder*>( aObject )
+            ->ResolveNextCandidateL() )
+        return 1;
+        }
+    else
+        {
+        return 0;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::FetchCandidatesL
+// ---------------------------------------------------------------------------
+//
+void CIceLocalCandidateFinder::FetchCandidatesL( 
+        TUint aStreamCollectionId, TUint aStreamId, TUint aComponentId,
+        TUint aAddrFamily, TBool aIPv6After )
+    {
+    __ICEDP( "CIceLocalCandidateFinder::FetchCandidatesL" )
+    
+    TInt numOfRequests = iPluginContainer.Count();
+    TCounter counter( aStreamId, numOfRequests );
+    __ASSERT_ALWAYS( KErrNotFound == iResolvingCnts.Find( 
+        counter, TCounter::MatchStreamId ), 
+        User::Leave( KErrAlreadyExists ) );
+    iResolvingCnts.AppendL( counter );
+    
+    // form requests
+    TIceNatPluginContainerIter iterator 
+        = TIceNatPluginContainerIter( iPluginContainer );
+    while ( !iterator.IsDone() )
+        {
+        CNATFWPluginApi* item = iterator++;
+
+        ScheduleResolveRequestL( *item, aStreamCollectionId, aStreamId, 
+            aComponentId, aAddrFamily, aIPv6After );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MIceNatPluginEventObs.
+// CIceLocalCandidateFinder::PluginEventOccured
+// ---------------------------------------------------------------------------
+//
+void CIceLocalCandidateFinder::PluginEventOccured( 
+        const CNATFWPluginApi* aPlugin, TUint aStreamId, 
+        MIceNatPluginEventObs::TNatPluginEvent aEventCode, 
+        TInt aErrorCode, TAny* aEventData, TUint aStreamConnectionId,
+        TUint aComponentId, TBool aIPv6After )
+    {
+    __ICEDP( "CIceLocalCandidateFinder::PluginEventOccured" )
+    
+    switch ( aEventCode )
+        {
+        case MIceNatPluginEventObs::ELocalCandidateFound:
+            {
+            if ( aEventData && NULL != aPlugin )
+                {
+                CNATFWCandidate* candidate 
+                    = reinterpret_cast<CNATFWCandidate*>( aEventData );
+                NewLocalCandidateFound( *aPlugin, *candidate );
+                }
+            else
+                {
+                __ICEDP( "CIceLocalCandidateFinder::PluginEventOccured, ELSE" )
+                ASSERT( EFalse );
+                }
+            }
+            break;
+        
+        case MIceNatPluginEventObs::EFetchingCompleted:
+            {
+            if ( KErrNone == aErrorCode )
+                {
+                iSucceeded = ETrue;
+                }
+
+            // At least one candidate must success
+            // otherwise pass error code upwards.
+            if ( ResolvingCompleted( aStreamId, aStreamConnectionId,
+                     aComponentId, aIPv6After ) )
+                {
+                iSucceeded ? aErrorCode = KErrNone : aErrorCode = KErrNotFound;
+                iSucceeded = EFalse;
+
+                iEventObserver.PluginEventOccured( NULL, aStreamId,
+                     aEventCode, aErrorCode, aEventData, aStreamConnectionId,
+                     aComponentId, aIPv6After );
+                }
+            }
+            break;
+
+        default:
+            __ICEDP( "CIceLocalCandidateFinder::PluginEventOccured, DEFAULT" )
+            ASSERT( EFalse );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::ScheduleResolveRequestL
+// ---------------------------------------------------------------------------
+//
+void CIceLocalCandidateFinder::ScheduleResolveRequestL( 
+        const CNATFWPluginApi& aPlugin,
+        TUint aCollectionId, TUint aStreamId, TUint aComponentId,
+        TUint aAddrFamily, TBool aIPv6After )
+    {
+    __ICEDP( "CIceLocalCandidateFinder::ScheduleResolveRequestL" )
+    
+    TResolveRequest request( aPlugin,
+        aCollectionId, aStreamId, aComponentId, 
+        TResolveRequest::ERequestNotIssued, aAddrFamily, aIPv6After );
+    iResolveRequests.AppendL( request );
+    
+    if ( !iTimer->IsActive() )
+        {
+        TCallBack callBack( 
+            CIceLocalCandidateFinder::ResolveNextCandidate, this );
+        iTimer->Start( 
+            0, iSessionData.TaTimerValue() * KMsToUsFactor, callBack );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::ResolveNextCandidateL
+// ---------------------------------------------------------------------------
+//
+void CIceLocalCandidateFinder::ResolveNextCandidateL()
+    {
+    TResolveRequest searchItem( TResolveRequest::ERequestNotIssued );
+    TInt reqIndex = iResolveRequests.Find( 
+        searchItem, TResolveRequest::MatchState );
+    
+    if ( KErrNotFound != reqIndex )
+        {
+        __ICEDP( "CIceLocalCandidateFinder::ResolveNextCandidateL" )
+        
+        TResolveRequest& request( iResolveRequests[reqIndex] );
+        request.SetState( TResolveRequest::ERequestOngoing );
+        
+        CNATFWPluginApi* plugin
+            = const_cast<CNATFWPluginApi*>( request.Plugin() );
+        ASSERT( NULL != plugin );
+        
+        TInt error( KErrNone );
+        if ( KNatPluginIdNokiaHost() == plugin->PluginIdentifier() )
+            {
+            // Create connection with desired address family
+            TUint addrFamily( request.AddrFamily() );
+            TRAP( error, plugin->FetchCandidateL( request.StreamId(),
+                RetransmissionTimeOut(), addrFamily ) );
+            if ( KErrNone != error )
+                {
+                PluginEventOccured( plugin, request.StreamId(), 
+                    MIceNatPluginEventObs::EFetchingCompleted, error, NULL );
+                }
+            else
+                {
+                CIceHostResolver* host
+                    = reinterpret_cast<CIceHostResolver*>( plugin );
+                iLocalAddr = host->LocalAddress( 
+                    request.StreamId(), addrFamily );
+                ASSERT( !iLocalAddr.IsUnspecified() );
+                }
+            }
+        else
+            {
+            TRAP( error, plugin->FetchCandidateL( request.StreamId(), 
+                RetransmissionTimeOut(), iLocalAddr ) );
+            if ( KErrNone != error )
+                {
+                PluginEventOccured( plugin, request.StreamId(), 
+                    MIceNatPluginEventObs::EFetchingCompleted, error, NULL );
+                }
+            }
+        }
+    else
+        {
+        __ICEDP( "CIceLocalCandidateFinder::ResolveNextCandidateL, READY" )
+        
+        iTimer->Cancel();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::NewLocalCandidateFound
+// ---------------------------------------------------------------------------
+//
+void CIceLocalCandidateFinder::NewLocalCandidateFound( 
+        const CNATFWPluginApi& aPlugin,
+        CNATFWCandidate& aLocalCandidate )
+    {
+    __ICEDP("CIceLocalCandidateFinder::NewLocalCandidateFound")
+
+    TResolveRequest searchItem( aPlugin, aLocalCandidate.StreamId(), 
+        TResolveRequest::ERequestOngoing );
+    TInt index( iResolveRequests.Find( 
+        searchItem, TResolveRequest::MatchStreamStatePlugin ) );
+    
+    if ( KErrNotFound != index )
+        {
+        aLocalCandidate.SetStreamCollectionId( 
+            iResolveRequests[index].CollectionId() );
+        aLocalCandidate.SetComponentId( 
+            iResolveRequests[index].ComponentId() );
+        
+        TRAP_IGNORE( iPrioritizer->PrioritizeL( aLocalCandidate ) )
+        }
+    else
+        {
+        ASSERT( EFalse );
+        }
+    
+    TBool redundantCandidate( EFalse );
+    TInt error( KErrNone );
+    TRAP( error, redundantCandidate 
+        = iSessionData.AddLocalCandidateL( &aLocalCandidate ) )
+    
+    if ( ( !redundantCandidate ) && ( KErrNone == error ) )
+        {
+        iEventObserver.PluginEventOccured( 
+            NULL,
+            aLocalCandidate.StreamId(),
+            MIceNatPluginEventObs::ELocalCandidateFound,
+            KErrNone,
+            CNATFWCandidate::NewL( aLocalCandidate ) );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::ResolvingCompleted
+// ---------------------------------------------------------------------------
+//
+TBool CIceLocalCandidateFinder::ResolvingCompleted( TUint aStreamId,
+        TUint& aStreamCollectionId, TUint& aComponentId, TBool& aIPv6After )
+    {
+    __ICEDP( "CIceLocalCandidateFinder::ResolvingCompleted" )
+    
+    TCounter counter( aStreamId );
+    TInt streamInd = iResolvingCnts.Find( counter, TCounter::MatchStreamId );
+    ASSERT( KErrNotFound != streamInd );
+    
+    --iResolvingCnts[streamInd];
+    
+    TBool completed( iResolvingCnts[streamInd] == 0 );
+    if ( completed )
+        {
+        iResolvingCnts.Remove( streamInd );
+        
+        TResolveRequest request( aStreamId );
+        TInt reqIndex = iResolveRequests.Find( request, 
+            TResolveRequest::MatchStreamId );
+
+        while ( KErrNotFound != reqIndex )
+            {
+            aIPv6After = iResolveRequests[reqIndex].IPv6After();
+            if ( aIPv6After )
+                {
+                aStreamCollectionId
+                    = iResolveRequests[reqIndex].CollectionId();
+                aComponentId = iResolveRequests[reqIndex].ComponentId();
+                }
+                
+            iResolveRequests.Remove( reqIndex );
+            reqIndex = iResolveRequests.Find( request, 
+                TResolveRequest::MatchStreamId );
+            }
+        }
+    
+    return completed;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIceLocalCandidateFinder::RetransmissionTimeOut
+// Calculates RTO while being in gathering phase as specified in ICE-17, 16.
+// RTO = MAX (100ms, Ta * (number of pairs)), where the number of pairs
+// refers to the number of pairs of candidates with STUN or TURN servers.
+// ---------------------------------------------------------------------------
+//
+TUint CIceLocalCandidateFinder::RetransmissionTimeOut() const
+    {
+    // resolving requests for host plugin excluded in formula
+    TInt numOfHostRequests( 0 );
+    
+    TInt numOfRequests( iResolveRequests.Count() );
+    for ( TInt i = 0; i < numOfRequests; i++ )
+        {
+        if ( KNatPluginIdNokiaHost() == 
+            iResolveRequests[i].Plugin()->PluginIdentifier() )
+            {
+            numOfHostRequests++;
+            }
+        }
+    
+    TInt numOfPairs = iResolveRequests.Count() - numOfHostRequests;
+    numOfPairs >= 0 ? numOfPairs = numOfPairs : numOfPairs = 0;
+    
+    const TInt KMinimumRto( 100 );
+    return TUint( Max( KMinimumRto, 
+        iSessionData.TaTimerValue() * numOfPairs ) );
+    }