natfw/natfwstunplugin/src/natfwstunconnectionhandler.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwstunplugin/src/natfwstunconnectionhandler.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1243 @@
+/*
+* Copyright (c) 2006 - 2008 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:    Creates connection to Connection Multiplexer and STUN client.
+*                Handles connection specific issues and receives notifications
+*                through implemented observers. Sends notifications to NAT FW 
+*                Client through NAT Protocol Plug-in observer.
+*
+*/
+
+
+
+
+#include "mncmconnectionmultiplexer.h"
+#include <cnatfwsettingsapi.h>
+#include <mnatfwserversettings.h>
+#include "natfwcandidate.h"
+#include "mnatfwpluginobserver.h"
+#include "natfwstunbinding.h"
+#include "natfwstunclient.h"
+#include <mnatfwstunsettings.h>
+
+#include "natfwstunconnectionhandler.h"
+#include "natfwstunpluginlogs.h"
+#include "natfwstunrefreshtimer.h"
+#include "natfwstunstreamdata.h"
+#include "cstunasynccallback.h"
+#include "cnatfwstunserversettings.h"
+
+const TUint KDefaultRefreshInterval = 28000000;
+const TUint KDefaultStunSrvPort = 3478;
+const TUint KMicrosecFactor = 1000000;
+const TUint KTryAlternate = 300;
+const TInt KClientSpecificError = -11000;
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CNATFWStunConnectionHandler::CNATFWStunConnectionHandler(
+    const CNATFWPluginApi& aStunPlugin )
+    :
+    iStunRefreshInterval( KDefaultRefreshInterval ),
+    iStunPlugin( aStunPlugin )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::ConstructL(
+    MNATFWPluginObserver& aPluginObserver )
+    {
+    iTimerServ = CDeltaTimer::NewL( CActive::EPriorityStandard );
+    iStunRefreshTimer = CNATFWStunRefreshTimer::NewL( *this );
+    iAsyncCallback = CStunAsyncCallback::NewL( iStunPlugin, aPluginObserver );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+CNATFWStunConnectionHandler* CNATFWStunConnectionHandler::NewL( 
+    const CNATFWPluginApi& aStunPlugin,
+    MNATFWPluginObserver& aPluginObserver )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::NewL" )
+    CNATFWStunConnectionHandler* self = CNATFWStunConnectionHandler::NewLC(
+        aStunPlugin, aPluginObserver );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+CNATFWStunConnectionHandler* CNATFWStunConnectionHandler::NewLC( 
+    const CNATFWPluginApi& aStunPlugin,
+    MNATFWPluginObserver& aPluginObserver )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::NewLC" )
+    CNATFWStunConnectionHandler* self = new( ELeave ) 
+        CNATFWStunConnectionHandler( aStunPlugin );
+    CleanupStack::PushL( self );
+    self->ConstructL( aPluginObserver );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CNATFWStunConnectionHandler::~CNATFWStunConnectionHandler()
+    {
+    __STUNPLUGIN(
+        "CNATFWStunConnectionHandler::~CNATFWStunConnectionHandler start" )
+
+    iServerList.ResetAndDestroy();
+
+    delete iDomain;
+    delete iNatSettings;
+    iStunSettings = NULL;
+    delete iStunRefreshTimer;
+
+    TInt count( iStreamArray.Count() );
+    for ( TInt index = count - 1; index >= 0; index-- )
+        {
+        DeleteStream( index, ETrue );
+        }
+
+    iStreamArray.Close();
+    delete iStunClient;
+    delete iTimerServ;
+    iConnection.Close();
+    iConnMux = NULL;
+    delete iAsyncCallback;
+
+    __STUNPLUGIN(
+        "CNATFWStunConnectionHandler::~CNATFWStunConnectionHandler end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::PluginInitializeL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::PluginInitializeL(
+    TUint32 aIapId,
+    const TDesC8& aDomain,
+    MNcmConnectionMultiplexer& aMultiplexer )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::PluginInitializeL start" )
+
+    iConnMux = &aMultiplexer;
+    iDomain = aDomain.AllocL();
+    iNatSettings = CNATFWNatSettingsApi::NewL( *iDomain );
+    
+    iStunSettings = &iNatSettings->StunSettingsL();
+    
+    iNatSettings->RetrieveIapSettingsL( aIapId );
+    
+    // Generates Server list
+    this->GenerateServerListL();
+
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::PluginInitializeL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::ConnectServerL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::ConnectServerL(
+    const RSocketServ& aSocketServ,
+    const TName& aConnectionName )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::ConnectServerL start" )
+    
+    iSocketServ = aSocketServ;    
+    TName name( aConnectionName );
+    User::LeaveIfError( iConnection.Open( iSocketServ, name ) );
+    
+    this->TryNextServerL();
+    
+    // wait MNATFWStunClientObserver::STUNClientInitCompleted
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::ConnectServerL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::FetchCandidateL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::FetchCandidateL( TUint aStreamId,
+    TUint aRtoValue, TUint aAddrFamily, const TInetAddr& aBaseAddr )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::FetchCandidateL start" )
+    
+    __ASSERT_ALWAYS( iStunClient, User::Leave( KErrNotReady) );
+    __ASSERT_ALWAYS(
+        iStunClient->IsInitialized(), User::Leave( KErrNotReady) );
+
+    TUint connectionId( aBaseAddr.IsUnspecified() ?
+        iConnMux->CreateConnectionL( aStreamId, aAddrFamily ) :
+        iConnMux->CreateConnectionL( aStreamId, aBaseAddr ) );
+
+    TConnectionData connData;
+    connData.iConnectionId = connectionId;
+    connData.iStunSrvAddr.SetAddress( iStunClient->STUNServerAddrL().
+        Address() );
+    connData.iStunSrvAddr.SetPort( iStunClient->STUNServerAddrL().Port() );
+    
+    TInt index( IndexByStreamId( aStreamId ) );
+    
+    if ( KErrNotFound == index )
+        {
+        TUint32 iapID( 0 );
+        TInt qos( 0 );
+        
+        // The stream is new for the plug-in
+        iConnMux->RegisterIncomingConnectionObserverL( aStreamId, *this );
+        iConnMux->RegisterConnectionObserverL( aStreamId, *this );
+        
+        TStreamData streamData;
+        streamData.iStreamId = aStreamId;
+        iConnMux->GetStreamInfoL( aStreamId, iapID, qos,
+            streamData.iTransportProtocol );
+        streamData.iRtoValue = aRtoValue;
+        streamData.iConnArray.AppendL( connData );
+        CleanupClosePushL( streamData.iConnArray );
+        iStreamArray.AppendL( streamData );
+        CleanupStack::Pop( &streamData.iConnArray );
+        }
+    else
+        {
+        // Store new connection for the existing stream in array
+        iStreamArray[index].iConnArray.AppendL( connData );
+        }
+    
+    // Accept data only from STUN server
+    iConnMux->SetAcceptedFromAddressL( aStreamId, connectionId,
+        connData.iStunSrvAddr );
+    
+    // Set receiving and sending state active for the created connection
+    iConnMux->SetReceivingStateL( aStreamId, connectionId,
+        EStreamingStateActive );
+    
+    iConnMux->SetSendingStateL( aStreamId, connectionId,
+        connData.iStunSrvAddr, EStreamingStateActive );
+    // wait MNcmConnectionObserver::ConnectionNotify
+    
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::FetchCandidateL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::GetConnectionIdL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::GetConnectionIdL(
+    const CNATFWCandidate& aLocalCandidate,
+    TUint aStreamId,
+    TUint& aConnectionId )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::GetConnectionIdL start" )
+    
+    TInt streamInd( IndexByStreamId( aStreamId ) );
+    TInt connInd( KErrNotFound );
+    TBool connFound( EFalse );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connInd = iStreamArray[streamInd].iConnArray.Count() - 1;
+        }
+    
+    while ( KErrNotFound != streamInd && !connFound && ( 0 <= connInd ) )
+        {
+        TConnectionData* connection = ConnectionByIndex( streamInd, connInd );
+        
+        if ( CNATFWCandidate::EServerReflexive == aLocalCandidate.Type() &&
+            MatchAddresses( aLocalCandidate.Base(), connection->
+            iLocalCandidate->Base() ) && MatchAddresses( aLocalCandidate.
+            TransportAddr(), connection->iLocalCandidate->TransportAddr() ) )
+            {
+            connFound = ETrue;
+            aConnectionId = connection->iConnectionId;
+            }
+        
+        connInd--;
+        }
+    
+    __ASSERT_ALWAYS( connFound, User::Leave( KErrNotFound ) );
+    
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::GetConnectionIdL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::StartStunRefresh
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::StartStunRefresh()
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::StartStunRefresh start" )
+    
+    iStunRefreshStarted = EFalse;
+    iStunRefreshTimer->StartStunRefresh( iStunRefreshInterval );
+    
+    if ( iStunRefreshTimer->IsRunning() )
+        {
+        iStunRefreshStarted = ETrue;
+        }
+    
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::StartStunRefresh end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::CreateSTUNBindingL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::CreateSTUNBindingL( TUint aStreamId, 
+                                                      TUint aConnectionId )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::CreateSTUNBindingL" )
+    
+    TInt streamInd( IndexByStreamId( aStreamId ) );
+    TConnectionData* connection( NULL );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connection = ConnectionById( streamInd, aConnectionId );
+        }
+    
+    if ( connection )
+        {
+        CSTUNBinding* stunBinding = CSTUNBinding::NewL( *iStunClient,
+                                                        aStreamId,
+                                                        aConnectionId );
+        CleanupStack::PushL( stunBinding );
+        connection->iStunBinding = stunBinding;
+        
+        stunBinding->SendRequestL( connection->iStunSrvAddr, EFalse,
+            iStreamArray[streamInd].iRtoValue );
+        
+        CleanupStack::Pop( stunBinding );
+        // wait MStunClientObserver::STUNBindingEventOccurredL
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::SetReceivingStateL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::SetReceivingStateL(
+    const CNATFWCandidate& aLocalCandidate,
+    TNATFWStreamingState aState )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::SetReceivingStateL start" )
+    
+    TUint streamId( aLocalCandidate.StreamId() );
+    TUint connId( 0 );
+    TConnectionData* connection = NULL;
+    TRAPD( err, GetConnectionIdL( aLocalCandidate, streamId, connId ) );
+    
+    if ( !err )
+        {
+        TInt streamInd( IndexByStreamId( streamId ) );
+        connection = ConnectionById( streamInd, connId );
+        }
+    
+    if ( connection )
+        {
+        if ( EStreamingStateActive == aState )
+            {
+            if ( connection->iReceivingActivated  )
+                {
+                iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                    EActiveReceiving, streamId, KErrNone, NULL );
+                }
+            else
+                {
+                iConnMux->SetReceivingStateL( streamId, connId,
+                    EStreamingStateActive );
+                }
+            }
+        else
+            {
+            if ( !connection->iReceivingActivated )
+                {
+                iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                    EDeactiveReceiving, streamId, KErrNone, NULL );
+                }
+            else
+                {
+                iConnMux->SetReceivingStateL( streamId, connId,
+                    EStreamingStatePassive );
+                }
+            }
+        }
+    else
+        {
+        if ( EStreamingStateActive == aState )
+            {
+            iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                EActiveReceiving, streamId, KErrNotFound, NULL );
+            }
+        else
+            {
+            iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                EDeactiveReceiving, streamId, KErrNotFound, NULL );
+            }
+        }
+    
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::SetReceivingStateL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::SetSendingStateL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::SetSendingStateL(
+    const CNATFWCandidate& aLocalCandidate,
+    TNATFWStreamingState aState,
+    const TInetAddr& aDestAddr )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::SetSendingStateL start" )
+    
+    TUint streamId( aLocalCandidate.StreamId() );
+    TUint connId( 0 );
+    TConnectionData* connection = NULL;
+    TRAPD( err, GetConnectionIdL( aLocalCandidate, streamId, connId ) );
+    
+    if ( !err )
+        {
+        TInt streamInd( IndexByStreamId( streamId ) );
+        connection = ConnectionById( streamInd, connId );
+        }
+    
+    if ( connection )
+        {
+        // Client controls media connection, set address filtering
+        iConnMux->SetAcceptedFromAddressL( streamId, connId, aDestAddr );
+        
+        if ( EStreamingStateActive == aState )
+            {
+            if ( connection->iSendingActivated && MatchAddresses(
+                connection->iDestAddr, aDestAddr ) )
+                {
+                iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                    EActiveSending, streamId, KErrNone, NULL );
+                }
+            else
+                {
+                connection->iDestAddr.SetAddress( aDestAddr.Address() );
+                connection->iDestAddr.SetPort( aDestAddr.Port() );
+                
+                iConnMux->SetSendingStateL( streamId, connId, aDestAddr,
+                    EStreamingStateActive );
+                }
+            }
+        else
+            {
+            if ( !connection->iSendingActivated )
+                {
+                iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                    EDeactiveSending, streamId, KErrNone, NULL );
+                }
+            else
+                {
+                iConnMux->SetSendingStateL( streamId, connId, aDestAddr,
+                    EStreamingStatePassive );
+                }
+            }
+        }
+    else
+        {
+        if ( EStreamingStateActive == aState )
+            {
+            iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                EActiveSending, streamId, KErrNotFound, NULL );
+            }
+        else
+            {
+            iAsyncCallback->MakeCallbackL( TStunPluginCallbackInfo::
+                EDeactiveSending, streamId, KErrNotFound, NULL );
+            }
+        }
+    
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::SetSendingStateL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// From base class MStunClientObserver.
+// CNATFWStunConnectionHandler::STUNClientInitCompleted
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::STUNClientInitCompleted(
+    const CSTUNClient& /*aClient*/, TInt aCompletionCode )
+    {
+    __STUNPLUGIN_INT1( "CNATFWStunConnectionHandler::STUNClientInitCompleted \
+         start - Completion code:", aCompletionCode )
+
+    TUint streamId( 0 );
+   
+    if ( KErrNone == aCompletionCode )
+        {
+        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+            TStunPluginCallbackInfo::EConnectServer, streamId,
+            aCompletionCode, NULL ) )
+        }
+    else
+        {
+        TInt error( KErrNone );
+
+        TRAP( error, TryNextServerL() );
+            
+        if ( KErrNone != error )
+            {
+            delete iStunClient;
+            iStunClient = NULL;
+            
+            TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                TStunPluginCallbackInfo::EConnectServer, streamId,
+                ( KClientSpecificError + aCompletionCode ), NULL ) )
+            }
+        }
+    
+    __STUNPLUGIN(
+        "CNATFWStunConnectionHandler::STUNClientInitCompleted end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// From base class MStunClientObserver
+// CNATFWStunConnectionHandler::STUNBindingEventOccurredL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::STUNBindingEventOccurredL(
+    TSTUNBindingEvent aEvent, 
+    const CBinding& aBinding )
+    {
+    __STUNPLUGIN( 
+        "CNATFWStunConnectionHandler::STUNBindingEventOccurredL start" )
+        
+    const CSTUNBinding& stunBinding =
+        static_cast<const CSTUNBinding&>( aBinding );
+    TUint streamId( stunBinding.StreamId() );
+    TUint connId( stunBinding.ConnectionId() );
+    
+    TInt streamInd( IndexByStreamId( streamId ) );
+    TConnectionData* connection( NULL );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connection = ConnectionById( streamInd, connId );
+        }
+    
+    if ( connection )
+        {
+        switch ( aEvent )
+            {
+            case EPublicAddressResolved:
+                {
+                if ( !connection->iLocalCandidate )
+                    {
+                    if ( iStunRefreshTimer && !iStunRefreshStarted )
+                        {
+                        StartStunRefresh();
+                        }
+                    
+                    TInetAddr publicAddr;
+                    publicAddr.SetAddress( stunBinding.PublicAddr().
+                        Address() );
+                    publicAddr.SetPort( stunBinding.PublicAddr().Port() );
+                    
+                    __STUNPLUGIN_ADDRLOG( "CNATFWStunConnectionHandler::\
+                    STUNBindingEventOccurredL  Adress Resolved ADDRESS: ",
+                        publicAddr )
+                    
+                    CNATFWCandidate* newCandidate = CNATFWCandidate::NewL();
+                    CleanupStack::PushL( newCandidate );
+                    
+                    // Set candidate parameters
+                    newCandidate->SetStreamId( streamId );
+                    newCandidate->SetType(
+                        CNATFWCandidate::EServerReflexive );
+                    TInetAddr baseAddr = iConnMux->LocalIPAddressL(
+                        streamId, connId );
+   
+                    newCandidate->SetBase( baseAddr );
+                    newCandidate->SetTransportAddrL( publicAddr );
+                    newCandidate->SetTransportProtocol(
+                        iStreamArray[streamInd].iTransportProtocol );
+                    
+                    CNATFWCandidate* copyCandidate = CNATFWCandidate::NewL(
+                        *newCandidate );
+                    connection->iLocalCandidate = copyCandidate;
+                    
+                    iAsyncCallback->MakeCallbackL(
+                        TStunPluginCallbackInfo::ELocalCandidateFound,
+                            streamId, KErrNone, newCandidate );
+                    
+                    iAsyncCallback->MakeCallbackL(
+                        TStunPluginCallbackInfo::EFetchingEnd, streamId,
+                        KErrNone, NULL );
+                    
+                    CleanupStack::Pop( newCandidate );
+                    }
+                }
+                break;
+
+            case ECredentialsRejected:
+                {
+                // STUN server rejected the credentials provided that were
+                // set with CSTUNClient::SetCredentialsL. Application
+                // should obtain valid credentials and then use
+                // CSTUNClient::SetCredentialsL.
+                iAsyncCallback->MakeCallbackL(
+                    TStunPluginCallbackInfo::EFetchingEnd, streamId,
+                    ( KClientSpecificError + KErrPermissionDenied ),
+                    NULL );
+
+                // Remove failed entry from array
+                DeleteStream( streamInd, ETrue );
+                }
+                break;
+            }
+        }
+
+    __STUNPLUGIN(
+        "CNATFWStunConnectionHandler::STUNBindingEventOccurredL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// From base class MStunClientObserver
+// CNATFWStunConnectionHandler::STUNBindingErrorOccurred
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::STUNBindingErrorOccurred(
+    const CBinding& aBinding,
+    TInt aError )
+    {
+    __STUNPLUGIN(
+        "CNATFWStunConnectionHandler::STUNBindingErrorOccurred start" )
+
+    const CSTUNBinding& stunBinding =
+        static_cast<const CSTUNBinding&>( aBinding );
+    TUint streamId( stunBinding.StreamId() );
+    TUint connId( stunBinding.ConnectionId() );
+    
+    TInt streamInd( IndexByStreamId( streamId ) );
+    TConnectionData* connection( NULL );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connection =  ConnectionById( streamInd, connId );
+        }
+    
+    if ( connection )
+        {
+        if ( !connection->iLocalCandidate )
+            {
+            if ( KTryAlternate == aError )
+                {
+                __STUNPLUGIN( "CNATFWStunConnectionHandler::\
+                STUNBindingErrorOccurred  KTryAlternate == aError" )
+                
+                connection->iStunSrvAddr.SetAddress( stunBinding.
+                    AlternateServerAddr().Address() );
+                connection->iStunSrvAddr.SetPort( stunBinding.
+                    AlternateServerAddr().Port() );
+                
+                delete connection->iStunBinding;
+                connection->iStunBinding = NULL;
+                
+                TRAP_IGNORE( iConnMux->SetSendingStateL( streamId, connId,
+                    connection->iStunSrvAddr, EStreamingStateActive ) )
+                // wait MNcmConnectionObserver::ConnectionNotify
+                }
+            else
+                {
+                // If error occurs when trying to fetch candidate
+                TInt errcode( KClientSpecificError + ( aError ) );
+                TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                    TStunPluginCallbackInfo::EFetchingEnd, streamId,
+                        errcode, NULL ) )
+
+                // Remove failed entry from array
+                DeleteStream( streamInd, ETrue );
+                }
+            }
+        else
+            {
+            // Do nothing if error occurs when doing binding refresh
+            }
+        }
+
+    __STUNPLUGIN(
+        "CNATFWStunConnectionHandler::STUNBindingErrorOccurred end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNcmIncomingConnectionObserver
+// CNATFWStunConnectionHandler::IncomingMessageL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::IncomingMessageL(
+    TUint aStreamId,
+    const TDesC8& aMessage,
+    const TInetAddr& /*aLocalAddr*/,
+#ifdef _DEBUG
+    const TInetAddr& aFromAddr,
+    const TInetAddr& aPeerRemoteAddr,
+#else
+    const TInetAddr& /*aFromAddr*/,
+    const TInetAddr& /*aPeerRemoteAddr*/,
+#endif
+    TBool& aConsumed )
+    {
+    __STUNPLUGIN_ADDRLOG(
+        "CNATFWStunConnectionHandler::IncomingMessageL FROMADDR", aFromAddr )
+    __STUNPLUGIN_ADDRLOG(
+        "CNATFWStunConnectionHandler::IncomingMessageL PEERADDR",
+            aPeerRemoteAddr )
+    
+    TInetAddr peerAddrFromIndication( KAFUnspec );
+    HBufC8* indicationData( NULL );
+    TInt consumingBindingInd( KErrNotFound );
+    
+    TInt streamInd( IndexByStreamId( aStreamId ) );
+    TInt connInd( KErrNotFound );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connInd = iStreamArray[streamInd].iConnArray.Count() - 1;
+        }
+
+    // Offer message for every binding in the stream until consumed
+    while ( KErrNotFound != streamInd && KErrNotFound == consumingBindingInd
+        && ( 0 <= connInd ) )
+        {
+        __STUNPLUGIN( "CNATFWStunConnectionHandler::IncomingMessageL\
+        HandleDataL method to be called" )
+        
+        TBool consumed( EFalse );
+        TConnectionData* connection = ConnectionByIndex( streamInd, connInd );
+        
+        if ( connection->iStunBinding )
+            {
+            if ( indicationData )
+                {
+                connection->iStunBinding->HandleDataL( *indicationData,
+                    consumed, peerAddrFromIndication );
+                }
+            else
+                {
+                indicationData = connection->iStunBinding->HandleDataL(
+                    aMessage, consumed, peerAddrFromIndication );
+                }
+            }
+        
+        if ( consumed )
+            {
+            consumingBindingInd = connInd;
+            aConsumed = ETrue;
+            }
+        
+        connInd--;
+        }
+    
+    delete indicationData;
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNcmConnectionObserver
+// CNATFWStunConnectionHandler::ConnectionNotify
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::ConnectionNotify(
+    TUint aStreamId,
+    TUint aConnectionId,
+    TConnectionNotifyType aType,
+    TInt aError )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::ConnectionNotify start" )
+    
+    TInt streamInd( IndexByStreamId( aStreamId ) );
+    TConnectionData* connection( NULL );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connection = ConnectionById( streamInd, aConnectionId );
+        }
+    
+    if ( connection )
+        {
+        if ( aError || EConnectionError == aType )
+            {
+            if ( !connection->iLocalCandidate )
+                {
+                // If error occurs when trying to fetch candidate
+                TInt errcode( KClientSpecificError + ( aError ) );
+                TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                    TStunPluginCallbackInfo::EFetchingEnd, aStreamId, errcode,
+                        NULL ) )
+                }
+            else
+                {
+                TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                    TStunPluginCallbackInfo::EError, aStreamId, aError,
+                        NULL ) )
+                }
+            
+            // Remove failed entry from array
+            DeleteStream( streamInd, ETrue );
+            }
+        else
+            {
+            switch ( aType )
+                {
+                case ESendingActivated:
+                    {
+                    connection->iSendingActivated = ETrue;
+                    
+                    if ( connection->iLocalCandidate )
+                        {
+                        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                            TStunPluginCallbackInfo::EActiveSending,
+                                aStreamId, KErrNone, NULL ) )
+                        }
+                    else
+                        {
+                        // Candidate fetching ongoing
+                        if ( !connection->iStunBinding )
+                            {
+                            TRAP_IGNORE( CreateSTUNBindingL( aStreamId,
+                                aConnectionId ) )
+                            }
+                        }
+                    }
+                    break;
+                
+                case EReceivingActivated:
+                    {
+                    connection->iReceivingActivated = ETrue;
+                    
+                    if ( connection->iLocalCandidate )
+                        {
+                        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                            TStunPluginCallbackInfo::EActiveReceiving,
+                                aStreamId, KErrNone, NULL ) )
+                        }
+                    }
+                    break;
+                
+                case ESendingDeactivated:
+                    {
+                    connection->iSendingActivated = EFalse;
+                    
+                    if ( connection->iLocalCandidate )
+                        {
+                        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                            TStunPluginCallbackInfo::EDeactiveSending,
+                                aStreamId, KErrNone, NULL ) )
+                        }
+                    }
+                    break;
+                
+                case EReceivingDeactivated:
+                    {
+                    connection->iReceivingActivated = EFalse;
+                    
+                    if ( connection->iLocalCandidate )
+                        {
+                        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                            TStunPluginCallbackInfo::EDeactiveReceiving,
+                                aStreamId, KErrNone, NULL ) )
+                        }
+                    }
+                    break;
+                
+                case EConnectionRemoved:
+                    {
+                    DeleteStream( streamInd, EFalse );
+                    }
+                    break;
+ 
+                 case EFirstMediaPacketSent:
+                    {
+                    connection->iMediaSendingActivated = ETrue;
+                    }
+                    break;                       
+                }
+            }
+        }
+
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::ConnectionNotify end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNATFWRefreshObserver
+// CNATFWStunConnectionHandler::BindingRefreshL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::BindingRefreshL()
+    {
+    TInt streamCount( iStreamArray.Count() );
+    
+    for ( TInt streamInd = 0; streamInd < streamCount; streamInd++ )
+        {
+        TInt connCount( iStreamArray[streamInd].iConnArray.Count() );
+        
+        for ( TInt connInd = 0; connInd < connCount; connInd++ )
+            {
+            TConnectionData* connection = ConnectionByIndex( streamInd,
+                connInd );
+            
+            if ( !connection->iMediaSendingActivated )
+                {
+                connection->iStunBinding->SendRequestL( connection->
+                    iStunSrvAddr, EFalse, iStreamArray[streamInd].iRtoValue );
+                }
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::DeleteStream
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::DeleteStream( TUint aStreamInd,
+    TBool aRemoveMuxConn )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::DeleteStream, start" )
+    ASSERT( aStreamInd < TUint( iStreamArray.Count() ) );
+    
+    TRAP_IGNORE( 
+        iConnMux->UnregisterIncomingConnectionObserverL(
+            iStreamArray[aStreamInd].iStreamId, *this ) )
+    TRAP_IGNORE( 
+        iConnMux->UnregisterConnectionObserverL(
+            iStreamArray[aStreamInd].iStreamId, *this ) )
+    
+    // Remove the stream's connections
+    TInt connIndex( iStreamArray[aStreamInd].iConnArray.Count() - 1 );
+    
+    for ( TInt i( connIndex ); i >= 0; i-- )
+        {
+        TConnectionData* connection = ConnectionByIndex( aStreamInd, i );
+        
+        if( connection->iStunBinding )
+            {
+            connection->iStunBinding->CancelRequest();
+            
+            delete connection->iStunBinding;
+            connection->iStunBinding = NULL;
+            delete connection->iLocalCandidate;
+            connection->iLocalCandidate = NULL;
+            }
+        
+        if ( aRemoveMuxConn )
+            {
+            TRAP_IGNORE( iConnMux->RemoveConnectionL(
+                iStreamArray[aStreamInd].iStreamId, connection->
+                    iConnectionId ) )
+            }
+        
+        iStreamArray[aStreamInd].iConnArray.Remove( i );
+        }
+    
+    iStreamArray[aStreamInd].iConnArray.Close();
+    iStreamArray.Remove( aStreamInd );
+    
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::DeleteStream, end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::IndexByStreamId
+// ---------------------------------------------------------------------------
+//
+TInt CNATFWStunConnectionHandler::IndexByStreamId( TUint aStreamId )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::IndexByStreamId" )
+    
+    TInt index( iStreamArray.Count() - 1 );
+    
+    while ( 0 <= index )
+        {
+        if ( aStreamId == iStreamArray[index].iStreamId )
+            {
+            return index;
+            }
+        
+        index--;
+        }
+    
+    return KErrNotFound;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::GenerateServerListL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::GenerateServerListL()
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::GenerateServerListL start" )
+    
+    RPointerArray<MNATFWServerSettings> serverArray;
+    iStunSettings->GetStunServerArrayL( serverArray );
+    
+    CleanupClosePushL( serverArray );
+    TInt count( serverArray.Count() );
+    
+    HBufC8* serverAddress =
+        iStunSettings->LatestConnectedServerAddr().AllocLC();
+    TUint latestPort = iStunSettings->LatestConnectedServerPort();
+    
+    // Add Latest connected STUN server
+    if ( serverAddress->Compare( KNullDesC8 ) )
+        {
+        __STUNPLUGIN( "CNATFWStunConnectionHandler::GenerateServerListL\
+        - Latest stun server added" )
+        
+        CStunServerSettings* settings = CStunServerSettings::NewLC();
+        settings->SetAddressL( *serverAddress );
+        settings->SetPort( latestPort );
+        
+        for ( TInt index( 0 ); index < count; index++ )
+            {
+            if ( *serverAddress == serverArray[index]->Address() &&
+                serverArray[index]->Username().Length() &&
+                serverArray[index]->Password().Length() )
+                {
+                settings->SetUsernameL( serverArray[index]->Username() );
+                settings->SetPasswordL( serverArray[index]->Password() );
+                break;
+                }
+            }
+        
+        iServerList.AppendL( settings );
+        CleanupStack::Pop( settings );
+        }
+    
+    CleanupStack::PopAndDestroy( serverAddress );
+    
+    // Add provisioned servers
+    for ( TInt index( 0 ); index < count; index++ )
+        {
+        CStunServerSettings* settings = CStunServerSettings::NewLC();
+        
+        settings->SetAddressL( serverArray[index]->Address() );
+        settings->SetPort( serverArray[index]->Port() );
+        
+        if ( serverArray[index]->Username().Length() &&
+            serverArray[index]->Password().Length() )
+            {
+            settings->SetUsernameL( serverArray[index]->Username() );
+            settings->SetPasswordL( serverArray[index]->Password() );
+            }
+        
+        if ( settings->Address().Compare( KNullDesC8 ) )
+            {
+            __STUNPLUGIN( "CNATFWStunConnectionHandler::GenerateServerListL\
+            - provisioned server added" )
+            iServerList.AppendL( settings );
+            }
+        
+        CleanupStack::Pop( settings );
+        }
+    
+    // Domain
+    CStunServerSettings* settings = CStunServerSettings::NewLC();
+    settings->SetAddressL( *iDomain );
+    settings->SetPort( ( latestPort ) ? latestPort : KDefaultStunSrvPort );
+    
+    for ( TInt index( 0 ); index < count; index++ )
+        {
+        if ( *iDomain == serverArray[index]->Address() &&
+            serverArray[index]->Username().Length() &&
+            serverArray[index]->Password().Length() )
+            {
+            settings->SetUsernameL( serverArray[index]->Username() );
+            settings->SetPasswordL( serverArray[index]->Password() );
+            break;
+            }
+        }
+    
+    iServerList.AppendL( settings );
+    CleanupStack::Pop( settings );
+    
+    CleanupStack::PopAndDestroy( &serverArray );
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::GenerateServerListL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::TryNextServerL
+// ---------------------------------------------------------------------------
+//
+void CNATFWStunConnectionHandler::TryNextServerL()
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::TryNextServerL start" )
+    
+    delete iStunClient;
+    iStunClient = NULL;
+    
+    _LIT8( KZeroAddrIpv4_1, "0" );
+    _LIT8( KZeroAddrIpv4_2, "0.0" );
+    _LIT8( KZeroAddrIpv4_3, "0.0.0" );
+    _LIT8( KZeroAddrIpv4_4, "0.0.0.0" );
+    _LIT8( KZeroAddrIpv6, "::" );
+        
+    if ( iServerIndex < iServerList.Count() )
+        {
+        TInt index( iServerIndex );
+        iServerIndex++;
+        
+        if ( iServerList[index]->Address().Compare( KZeroAddrIpv4_1 ) == 0 || 
+             iServerList[index]->Address().Compare( KZeroAddrIpv4_2 ) == 0 ||
+             iServerList[index]->Address().Compare( KZeroAddrIpv4_3 ) == 0 ||
+             iServerList[index]->Address().Compare( KZeroAddrIpv4_4 ) == 0 ||
+             iServerList[index]->Address().Compare( KZeroAddrIpv6 ) == 0 )
+            {
+            __STUNPLUGIN("CNATFWStunConnectionHandler::TryNextServerL address\
+            '0.0.0.0' or '::' are not accepted, stop public IP resolving..")
+            User::Leave( KErrCouldNotConnect );
+            }
+        
+        TInt refresh( iNatSettings->RefreshIntervalUdp() );
+        iStunRefreshInterval =
+            ( refresh ) ? ( refresh * KMicrosecFactor ) :
+                KDefaultRefreshInterval;
+        
+        TInt retransmitInterval( iStunSettings->RetransmissionTimeout() );
+        TBool useSharedSecret( iNatSettings->UseSharedSecret() );
+        
+        TBool useLongTerm( EFalse );
+        
+        if ( useSharedSecret &&
+            iServerList[index]->Username() &&
+            iServerList[index]->Password() )
+            {
+            useLongTerm = ETrue;
+            }
+        
+        TUint port = iServerList[index]->Port() ?
+            iServerList[index]->Port() : KDefaultStunSrvPort;
+        
+        iStunClient = CSTUNClient::NewL( retransmitInterval,
+                                         iServerList[index]->Address(),
+                                         port,
+                                         KStun,
+                                         iSocketServ,
+                                         iConnection,
+                                         *iTimerServ,
+                                         *this,
+                                         useSharedSecret,
+                                         EFalse,
+                                         EFalse,
+                                         iConnMux );
+        
+        if ( useLongTerm )
+            {
+            TRAP_IGNORE( iStunClient->SetCredentialsL( *iServerList[index]->
+                Username(), *iServerList[index]->Password() ) )
+            }
+        }
+    else
+        {
+        User::Leave( KErrNotFound );
+        }
+    
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::TryNextServerL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::ConnectionById
+// ---------------------------------------------------------------------------
+//
+TConnectionData* CNATFWStunConnectionHandler::ConnectionById(
+    TUint aStreamInd,
+    TUint aConnectionId )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::ConnectionById" )
+    
+    TInt index( iStreamArray[aStreamInd].iConnArray.Count() - 1 );
+    
+    while ( 0 <= index )
+        {
+        if ( aConnectionId == iStreamArray[aStreamInd].iConnArray[index].
+            iConnectionId )
+            {
+            return &iStreamArray[aStreamInd].iConnArray[index];
+            }
+        
+        index--;
+        }
+        
+    return NULL;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::ConnectionByIndex
+// ---------------------------------------------------------------------------
+//
+TConnectionData* CNATFWStunConnectionHandler::ConnectionByIndex(
+    TUint aStreamInd,
+    TUint aConnectionInd )
+    {
+    __STUNPLUGIN( "CNATFWStunConnectionHandler::ConnectionByIndex" )
+    
+    return &iStreamArray[aStreamInd].iConnArray[aConnectionInd];
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::MatchAddresses
+// ---------------------------------------------------------------------------
+//
+TBool CNATFWStunConnectionHandler::MatchAddresses( const TInetAddr& aAddr1,
+    const TInetAddr& aAddr2 ) const
+    {
+    // CmpAddr does not interpret IPv4 and IPv4 mapped/compatible addresses
+    // as same even if they represent same address. Thus extra testing is
+    // needed to handle that case.
+    TBool isMatch = ( aAddr1.CmpAddr( aAddr2 ) || ( aAddr1.Address() ==
+        aAddr2.Address() && aAddr1.Port() == aAddr2.Port() ) );
+    
+    return isMatch;
+    }
+
+// End of file