natfw/natfwturnplugin/src/natfwturnconnectionhandler.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwturnplugin/src/natfwturnconnectionhandler.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1859 @@
+/*
+* 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 TURN 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 "natfwstunrelaybinding.h"
+#include "natfwstunclient.h"
+#include <mnatfwturnsettings.h>
+
+#include "natfwturnconnectionhandler.h"
+#include "natfwturnpluginlogs.h"
+#include "natfwturnrefreshtimer.h"
+#include "natfwturnstreamdata.h"
+#include "natfwturnactivedestinationtimer.h"
+#include "cturnasynccallback.h"
+#include "cnatfwturnserversettings.h"
+
+#include "natfwunsafmessage.h"
+#include "natfwunsafmessagefactory.h"
+#include "natfwunsafremoteaddressattribute.h"
+#include "natfwunsafdataattribute.h"
+#include "natfwunsaftcprelaypacket.h"
+
+const TUint KDefaultStunSrvPort = 3478;
+const TUint KDefaultRefreshInterval = 28000000;
+const TUint KMicrosecFactor = 1000000;
+const TUint32 KWaitTimeAfterReset = 5000000;
+// transitioning time changed from 3000000=>0 to get ICE work
+const TUint32 KDefaultSrvTransitioningTime = 0;
+const TUint32 KRetryTimeAfter439 = 5000;
+const TUint KNoBinding = 437;
+const TUint KServerTransitioning = 439;
+const TUint KTryAlternate = 300;
+const TInt KClientSpecificError = -11000;
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CNATFWTurnConnectionHandler::CNATFWTurnConnectionHandler(
+    const CNATFWPluginApi& aTurnPlugin )
+    :
+    iTurnPlugin( aTurnPlugin )
+    {
+
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::ConstructL(
+    MNATFWPluginObserver& aPluginObserver )
+    {
+    iTimerServ = CDeltaTimer::NewL( CActive::EPriorityStandard );
+    iTurnRefreshTimer = CNATFWTurnRefreshTimer::NewL( *this );
+    iActiveDestinationTimer = CNATFWTurnActiveDestinationTimer::NewL( *this );
+    iAsyncCallback = CTurnAsyncCallback::NewL( iTurnPlugin, aPluginObserver );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+CNATFWTurnConnectionHandler* CNATFWTurnConnectionHandler::NewL(
+    const CNATFWPluginApi& aTurnPlugin,
+    MNATFWPluginObserver& aPluginObserver )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::NewL" )
+    CNATFWTurnConnectionHandler* self = CNATFWTurnConnectionHandler::NewLC(
+        aTurnPlugin, aPluginObserver );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian constructor
+// ---------------------------------------------------------------------------
+//
+CNATFWTurnConnectionHandler* CNATFWTurnConnectionHandler::NewLC(
+    const CNATFWPluginApi& aTurnPlugin,
+    MNATFWPluginObserver& aPluginObserver )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::NewLC" )
+    CNATFWTurnConnectionHandler* self =
+        new( ELeave ) CNATFWTurnConnectionHandler( aTurnPlugin );
+    CleanupStack::PushL( self );
+    self->ConstructL( aPluginObserver );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CNATFWTurnConnectionHandler::~CNATFWTurnConnectionHandler()
+    {
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::~CNATFWTurnConnectionHandler start" )
+
+    iServerList.ResetAndDestroy();
+
+    delete iDomain;
+    delete iNatSettings;
+    delete iTurnRefreshTimer;
+    delete iActiveDestinationTimer;
+
+    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;
+
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::~CNATFWTurnConnectionHandler end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::PluginInitializeL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::PluginInitializeL(
+    TUint32 aIapId,
+    const TDesC8& aDomain,
+    MNcmConnectionMultiplexer& aMultiplexer )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::PluginInitializeL start" )
+    iConnMux = &aMultiplexer;
+    delete iDomain;
+    iDomain = NULL;
+    iDomain = aDomain.AllocL();
+    delete iNatSettings;
+    iNatSettings = NULL;
+    iNatSettings = CNATFWNatSettingsApi::NewL( *iDomain );        
+    iNatSettings->RetrieveIapSettingsL( aIapId );
+    iTurnSettings = &iNatSettings->TurnSettingsL();
+    
+    // Generates Server list
+    this->GenerateServerListL();
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::PluginInitializeL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::ConnectServerL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::ConnectServerL(
+    const RSocketServ& aSocketServ,
+    const TName& aConnectionName )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::ConnectServerL start" )
+    
+    iSocketServ = aSocketServ;
+    TName name( aConnectionName );
+    User::LeaveIfError( iConnection.Open( iSocketServ, name ) );
+    this->TryNextServerL();
+    
+    // wait MNATFWStunClientObserver::STUNClientInitCompleted
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::ConnectServerL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::FetchCandidateL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::FetchCandidateL( TUint aStreamId,
+    TUint aRtoValue, TUint aAddrFamily, const TInetAddr& aBaseAddr )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::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.iServerAddr.SetAddress( iStunClient->STUNServerAddrL().
+        Address() );
+    connData.iServerAddr.SetPort( iStunClient->STUNServerAddrL().Port() );
+    connData.iLocalAddr = iConnMux->LocalIPAddressL( aStreamId,
+        connectionId );
+    
+    TInt index( IndexByStreamId( aStreamId ) );
+    
+    if ( KErrNotFound == index )
+        {
+        TUint32 iapID( 0 );
+        TInt qos( 0 );
+        
+        // The stream is new for the plug-in
+        iConnMux->RegisterConnectionObserverL( aStreamId, *this );
+        iConnMux->RegisterIncomingConnectionObserverL( aStreamId, *this );
+        iConnMux->RegisterOutgoingConnectionObserverL( aStreamId, *this );
+        iConnMux->RegisterMessageObserverL( 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 TURN server
+    iConnMux->SetAcceptedFromAddressL( aStreamId, connectionId, 
+        connData.iServerAddr );
+    
+    // Set receiving and sending state active for the created connection
+    iConnMux->SetReceivingStateL( aStreamId, connectionId,
+        EStreamingStateActive );
+    
+    iConnMux->SetSendingStateL( aStreamId, connectionId, connData.iServerAddr,
+        EStreamingStateActive );
+    // wait MNcmConnectionObserver::ConnectionNotify
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::FetchCandidateL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::GetConnectionIdL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::GetConnectionIdL(
+    const CNATFWCandidate& aLocalCandidate,
+    TUint aStreamId,
+    TUint& aConnectionId )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::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::ERelay == 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 ) );
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::GetConnectionIdL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::StartTurnRefresh
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::StartTurnRefresh()
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::StartTurnRefresh start" )
+    
+    iTurnRefreshStarted = EFalse;
+    iTurnRefreshTimer->StartTurnRefresh( iTurnRefreshInterval );
+    
+    if ( iTurnRefreshTimer->IsRunning() )
+        {
+        iTurnRefreshStarted = ETrue;
+        }
+
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::StartTurnRefresh end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::CreateTURNBindingL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::CreateTURNBindingL( TUint aStreamId,
+                                                      TUint aConnectionId )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::CreateTURNBindingL" )
+    
+    TInt streamInd( IndexByStreamId( aStreamId ) );
+    TConnectionData* connection( NULL );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connection = ConnectionById( streamInd, aConnectionId );
+        }
+    
+    if ( connection )
+        {
+        CSTUNRelayBinding* turnBinding = CSTUNRelayBinding::NewL(
+            *iStunClient, aStreamId, aConnectionId );
+        
+        CleanupStack::PushL( turnBinding );
+        delete connection->iTurnBinding;
+        connection->iTurnBinding = turnBinding;
+        turnBinding->AllocateRequestL( iStreamArray[streamInd].iRtoValue );
+        CleanupStack::Pop( turnBinding );
+        // wait MStunClientObserver::STUNBindingEventOccurredL
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::SetReceivingStateL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::SetReceivingStateL(
+    const CNATFWCandidate& aLocalCandidate,
+    TNATFWStreamingState aState )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::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( TTurnPluginCallbackInfo::
+                    EActiveReceiving, streamId, KErrNone, NULL );
+                }
+            else
+                {
+                iConnMux->SetReceivingStateL( streamId, connId,
+                    EStreamingStateActive );
+                }
+            }
+        else
+            {
+            if ( !connection->iReceivingActivated )
+                {
+                iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                    EDeactiveReceiving, streamId, KErrNone, NULL );
+                }
+            else
+                {
+                iConnMux->SetReceivingStateL( streamId, connId,
+                    EStreamingStatePassive );
+                }
+            }
+        }
+    else
+        {
+        if ( EStreamingStateActive == aState )
+            {
+            iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                EActiveReceiving, streamId, KErrNotFound, NULL );
+            }
+        else
+            {
+            iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                EDeactiveReceiving, streamId, KErrNotFound, NULL );
+            }
+        }
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::SetReceivingStateL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::SetSendingStateL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::SetSendingStateL(
+    const CNATFWCandidate& aLocalCandidate,
+    TNATFWStreamingState aState,
+    const TInetAddr& aDestAddr )
+    {
+    __TURNPLUGIN_ADDRLOG(
+    "CNATFWTurnConnectionHandler::SetSendingStateL start",
+        aDestAddr )
+    
+    TUint streamId( aLocalCandidate.StreamId() );
+    TUint connId( 0 );
+    TConnectionData* connection = NULL;
+    TInt streamInd( IndexByStreamId( streamId ) );
+    TRAPD( err, GetConnectionIdL( aLocalCandidate, streamId, connId ) );
+    
+    if ( !err )
+        {
+        connection = ConnectionById( streamInd, connId );
+        }
+    
+    if ( connection )
+        {
+        if ( EStreamingStateActive == aState && TConnectionData::
+            EActDestTransitioning == connection->iActDestState )
+            {
+            // Only Active Destination reset (sending passivation)
+            // can be done when in "Transitioning" state.
+            iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                EActiveSending, streamId, KErrNotReady, NULL );
+            }
+        else
+            {
+            if ( EStreamingStateActive == aState )
+                {
+                // Do Set Active Destination Request if the remote
+                // address differs from current active destination
+                
+                if ( !MatchAddresses( connection->iCurrentActDest,
+                    aDestAddr ) )
+                    {
+                    connection->iPeerAddr.SetAddress( aDestAddr.Address() );
+                    connection->iPeerAddr.SetPort( aDestAddr.Port() );
+                    
+                    if ( KProtocolInetTcp == iStreamArray[streamInd].
+                        iTransportProtocol )
+                        {
+                        // We need to do the Connect Request first
+                        // and have successfull response to it.
+                        connection->iTurnBinding->ConnectRequestL(
+                            connection->iPeerAddr );
+                        }
+                    else
+                        {
+                        connection->iTurnBinding
+                            ->SetActiveDestinationRequestL(
+                                connection->iPeerAddr, 
+                                connection->iTimerValue );
+                        }
+                    }
+                else
+                    {
+                    // No need to set this destination active again
+                    iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                        EActiveSending, streamId, KErrNone, NULL );
+                    }
+                }
+            else
+                {
+                // Plug-in's client wants to reset Active Destination.
+                connection->iPeerAddr = KAFUnspec;
+                
+                connection->iTurnBinding->SetActiveDestinationRequestL(
+                    connection->iPeerAddr, connection->iTimerValue );
+                }
+            }
+        }
+    else
+        {
+        if ( EStreamingStateActive == aState )
+            {
+            iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                EActiveSending, streamId, KErrNotFound, NULL );
+            }
+        else
+            {
+            iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                EDeactiveSending, streamId, KErrNotFound, NULL );
+            }
+        }
+    
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::SetSendingStateL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::IsRequestOrIndicationL
+// ---------------------------------------------------------------------------
+//
+TBool CNATFWTurnConnectionHandler::IsRequestOrIndicationL(
+    const TDesC8& aMessage ) const
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::IsRequestOrIndicationL" )
+
+    CNATFWUNSAFMessageFactory* decoder = CNATFWUNSAFMessageFactory::NewLC();
+    CNATFWUNSAFMessage* msg = decoder->DecodeL( aMessage );
+    CleanupStack::PopAndDestroy( decoder );
+
+    if ( CNATFWUNSAFMessage::EAllocateRequest == msg->Type() ||
+         CNATFWUNSAFMessage::EConnectRequest == msg->Type() ||
+         CNATFWUNSAFMessage::ESetActiveDestinationRequest == msg->Type() ||
+         CNATFWUNSAFMessage::ESendIndication == msg->Type() )
+        {
+        delete msg;
+        return ETrue;
+        }
+    else
+        {
+        delete msg;
+        return EFalse;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::IsTurnResponseL
+// ---------------------------------------------------------------------------
+//
+TBool CNATFWTurnConnectionHandler::IsTurnResponseL(
+    const TDesC8& aMessage ) const
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::IsTurnResponseL" )
+
+    CNATFWUNSAFMessageFactory* decoder = CNATFWUNSAFMessageFactory::NewLC();
+    CNATFWUNSAFMessage* msg = decoder->DecodeL( aMessage );
+    CleanupStack::PopAndDestroy( decoder );
+
+    if ( CNATFWUNSAFMessage::EAllocateResponse == msg->Type() ||
+         CNATFWUNSAFMessage::EAllocateErrorResponse == msg->Type() ||
+         CNATFWUNSAFMessage::ESetActiveDestinationResponse == msg->Type() ||
+         CNATFWUNSAFMessage::ESetActiveDestinationErrorResponse ==
+            msg->Type() ||
+         CNATFWUNSAFMessage::EConnectResponse == msg->Type() ||
+         CNATFWUNSAFMessage::EConnectErrorResponse == msg->Type() )
+        {
+        delete msg;
+        return ETrue;
+        }
+    else
+        {
+        delete msg;
+        return EFalse;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// From base class MStunClientObserver.
+// CNATFWTurnConnectionHandler::STUNClientInitCompleted
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::STUNClientInitCompleted(
+    const CSTUNClient& /*aClient*/,
+    TInt aCompletionCode )
+    {
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::STUNClientInitCompleted start" )
+    
+    if ( KErrNone == aCompletionCode )
+        {
+        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+            TTurnPluginCallbackInfo::EConnectServer, 0,
+            aCompletionCode, NULL ) )
+        }
+    else
+        {
+        TInt error( KErrNone );
+        TRAP( error, TryNextServerL() );
+        
+        if ( KErrNone != error )
+            {
+            delete iStunClient;
+            iStunClient = NULL;
+            
+            TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                TTurnPluginCallbackInfo::EConnectServer, 0,
+                ( KClientSpecificError + aCompletionCode), NULL ) )
+            }
+        }
+    
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::STUNClientInitCompleted end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// From base class MStunClientObserver
+// CNATFWTurnConnectionHandler::STUNBindingEventOccurredL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::STUNBindingEventOccurredL(
+    TSTUNBindingEvent aEvent,
+    const CBinding& aBinding )
+    {
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::STUNBindingEventOccurredL start" )
+    
+    const CSTUNRelayBinding& turnBinding =
+        static_cast<const CSTUNRelayBinding&>( aBinding );
+    TUint streamId( turnBinding.StreamId() );
+    TUint connId( turnBinding.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 ( iTurnRefreshTimer && !iTurnRefreshStarted )
+                        {
+                        StartTurnRefresh();
+                        }
+                    
+                    TInetAddr relayAddr;
+                    relayAddr.SetAddress( turnBinding.RelayAddr().Address() );
+                    relayAddr.SetPort( turnBinding.RelayAddr().Port() );
+                    
+                    __TURNPLUGIN_ADDRLOG( "CNATFWTurnConnectionHandler::\
+                    STUNBindingEventOccurredL  Adress Resolved ADDRESS: ",
+                        relayAddr )
+                    
+                    CNATFWCandidate* newCandidate = CNATFWCandidate::NewL();
+                    CleanupStack::PushL( newCandidate );
+                    
+                    // Set candidate parameters
+                    newCandidate->SetStreamId( streamId );
+                    newCandidate->SetType( CNATFWCandidate::ERelay );
+                    newCandidate->SetBase( relayAddr );
+                    newCandidate->SetTransportAddrL( relayAddr );
+                    newCandidate->SetTransportProtocol(
+                        iStreamArray[streamInd].iTransportProtocol );
+                    
+                    CNATFWCandidate* copyCandidate = CNATFWCandidate::NewL(
+                        *newCandidate );
+                    connection->iLocalCandidate = copyCandidate;
+                    
+                    iAsyncCallback->MakeCallbackL(
+                        TTurnPluginCallbackInfo::ELocalCandidateFound,
+                            streamId, KErrNone, newCandidate );
+                    
+                    iAsyncCallback->MakeCallbackL(
+                        TTurnPluginCallbackInfo::EFetchingEnd, streamId,
+                            KErrNone, NULL );
+                    
+                    CleanupStack::Pop( newCandidate );
+                    }
+                }
+                break;
+            
+            case ECredentialsRejected:
+                {
+                __TURNPLUGIN( "CNATFWTurnConnectionHandler::\
+                    STUNBindingEventOccurredL  Credentials Rejected" )
+                
+                // TURN server rejected the credentials provided that were
+                // set with CSTUNClient::SetCredentialsL. Application
+                // should obtain valid credentials and then use
+                // CSTUNClient::SetCredentialsL.
+                iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                    EFetchingEnd, streamId, ( KClientSpecificError +
+                        KErrPermissionDenied ), NULL );
+
+                // Remove failed entry from array
+                DeleteStream( streamInd, ETrue );
+                }
+                break;
+            
+            case ETCPConnectOk:
+                {
+                __TURNPLUGIN( "CNATFWTurnConnectionHandler::\
+                    STUNBindingEventOccurredL  TCP Connect Ok" )
+                
+                // After TCP connect is OK we can set Active Destination.
+                connection->iTurnBinding->SetActiveDestinationRequestL(
+                    connection->iPeerAddr, connection->iTimerValue );
+                }
+                break;
+            
+            // Success
+            case EActiveDestinationSet:
+                {
+                __TURNPLUGIN( "CNATFWTurnConnectionHandler::\
+                    STUNBindingEventOccurredL  Active Destination Set" )
+
+                if ( TConnectionData::EActDestNoneSet == connection->
+                    iActDestState && !connection->iPeerAddr.IsUnspecified() )
+                    {
+                    if ( connection->iActDestAlreadySetOnServer )
+                        {
+                        // Active Destination was reset on server. Media
+                        // flows in indications while trying to set the
+                        // Active Destination again after 5 seconds.
+                        iAsyncCallback->MakeCallbackL(
+                            TTurnPluginCallbackInfo::EActiveSending,
+                                iStreamArray[streamInd].iStreamId, KErrNone,
+                                    NULL );
+
+                        iActiveDestinationTimer->StartTimer(
+                            KWaitTimeAfterReset, iStreamArray[streamInd].
+                                iStreamId, connection->iConnectionId );
+                        }
+                    else
+                        {
+                        iAsyncCallback->MakeCallbackL(
+                            TTurnPluginCallbackInfo::EActiveSending,
+                                iStreamArray[streamInd].iStreamId, KErrNone,
+                                    NULL );
+                        
+                        iActiveDestinationTimer->StartTimer(
+                            KDefaultSrvTransitioningTime,
+                                iStreamArray[streamInd].iStreamId,
+                                    connection->iConnectionId );
+                        
+                        // If a successful response was received, but
+                        // there was a REMOTE-ADDRESS in the request, the
+                        // state machine transitions to the "Set" state
+                        // after three seconds, and the client sets the
+                        // active destination to the value of the REMOTE-
+                        // ADDRESS attribute that was in the request.
+                        }
+                    }
+                
+                // else If, while in the "None Set" state, the client
+                // sent a Set Active Destination request without a
+                // REMOTE-ADDRESS, and got a successful response,
+                // there is no change in state.
+                
+                else if ( TConnectionData::EActDestSet == connection->
+                    iActDestState )
+                    {
+                    if ( connection->iPeerAddr.IsUnspecified() ||
+                        !MatchAddresses( connection->iPeerAddr, connection->
+                        iCurrentActDest ) )
+                        {
+                        connection->iActDestState = TConnectionData::
+                            EActDestTransitioning;
+                        
+                        // the client enters the "Transitioning" state.
+                        // While in this state, the client MUST NOT send
+                        // a new Set Active Destination request. The value
+                        // of the active destination remains unchanged. In
+                        // addition, the client sets a timer. This timer
+                        // MUST have a value equal to the value of the
+                        // TIMER-VAL attribute from the Set Active
+                        // Destination response.  This is necessary for
+                        // coordinating the state machines between client
+                        // and server.
+                        
+                        iActiveDestinationTimer->StartTimer(
+                            connection->iTimerValue, iStreamArray[streamInd].
+                                iStreamId, connection->iConnectionId );
+                        }
+                    
+                    // In addition, if, while in the "Set" state, the
+                    // client sends a Set Active Destination request whose
+                    // REMOTE-ADDRESS attribute equals the current active
+                    // destination, and that request generates a success
+                    // response, the client remains in the "Set" state.
+                    }
+                else
+                    {
+                    // Only Active Destination reset request can be done when
+                    // in "Transitioning" state.
+                    if ( connection->iPeerAddr.IsUnspecified() )
+                        {
+                        iActiveDestinationTimer->StartTimer( connection->
+                            iTimerValue, iStreamArray[streamInd].iStreamId,
+                                connection->iConnectionId );
+                        }
+                    }
+                }
+                break;
+            }
+        }
+
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::STUNBindingEventOccurredL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// From base class MStunClientObserver
+// CNATFWTurnConnectionHandler::STUNBindingErrorOccurred
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::STUNBindingErrorOccurred(
+    const CBinding& aBinding,
+    TInt aError )
+    {
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::STUNBindingErrorOccurred start" )
+
+    const CSTUNRelayBinding& turnBinding =
+        static_cast<const CSTUNRelayBinding&>( aBinding );
+    TUint streamId( turnBinding.StreamId() );
+    TUint connId( turnBinding.ConnectionId() );
+    
+    TInt streamInd( IndexByStreamId( streamId ) );
+    TConnectionData* connection( NULL );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connection = ConnectionById( streamInd, connId );
+        }
+    
+    if ( connection )
+        {
+        if ( KNoBinding == aError && connection->iLocalCandidate )
+            {
+            // A 437 response implies that the allocation has been
+            // removed, and thus the state machine destroyed. A client
+            // MUST NOT send a new Set Active Destination request prior
+            // to the receipt of a response to the previous. The state
+            // machine will further limit the transmission of subsequent
+            // Set Active Destination requests.
+            TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                TTurnPluginCallbackInfo::EActiveSending, streamId,
+                    KErrNotFound, NULL ) )
+
+            // Remove entry from array as binding does not exist anymore
+            DeleteStream( streamInd, ETrue );
+            }
+        else if ( KServerTransitioning == aError && connection->
+            iLocalCandidate )
+            {
+            if ( TConnectionData::EActDestSet == connection->iActDestState )
+                {
+                // When this error is received, the client remains in the
+                // "Set" state. The client SHOULD retry its Set Active
+                // Destination request, but no sooner than 500ms after
+                // receipt of the 439 response.
+                iActiveDestinationTimer->StartTimer(
+                    KRetryTimeAfter439, iStreamArray[streamInd].iStreamId,
+                        connection->iConnectionId );
+                }
+            else if ( TConnectionData::EActDestNoneSet == connection->
+                iActDestState )
+                {
+                // Set Active Destination request was received by the
+                // server over UDP. However, the active destination is
+                // already set to another value. The client should reset
+                // the active destination, wait for 5 seconds and set the
+                // active destination to the new value.
+                connection->iActDestAlreadySetOnServer = ETrue;
+                
+                TRAP_IGNORE( connection->iTurnBinding->
+                    SetActiveDestinationRequestL( KAFUnspec, connection->
+                        iTimerValue ) )
+                }
+            else
+                {
+                // Not possible that this error occurs when in
+                // "transitioning" state
+                }
+            }
+        else
+            {
+            if ( !connection->iLocalCandidate )
+                {
+                if( KTryAlternate == aError )
+                    {
+                    __TURNPLUGIN( "CNATFWTurnConnectionHandler::\
+                    STUNBindingErrorOccurred  KTryAlternate == aError" )
+                    
+                    connection->iServerAddr.SetAddress( turnBinding.
+                        AlternateServerAddr().Address() );
+                    connection->iServerAddr.SetPort( turnBinding.
+                        AlternateServerAddr().Port() );
+                    
+                    delete connection->iTurnBinding;
+                    connection->iTurnBinding = NULL;
+                    
+                    TRAP_IGNORE( iConnMux->SetSendingStateL( streamId, connId,
+                        connection->iServerAddr, EStreamingStateActive ) )
+                    // wait MNcmConnectionObserver::ConnectionNotify
+                    }
+                else
+                    {
+                    // If error occurs when trying to fetch candidate
+                    TInt errcode( KClientSpecificError + ( aError ) );
+                    TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                        TTurnPluginCallbackInfo::EFetchingEnd, streamId,
+                            errcode, NULL ) )
+                    
+                    // Remove failed entry from array
+                    DeleteStream( streamInd, ETrue );
+                    }
+                }
+            else
+                {
+                // Do nothing if error occurs when doing binding refresh
+                }
+            }
+        }
+
+    __TURNPLUGIN(
+        "CNATFWTurnConnectionHandler::STUNBindingErrorOccurred end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNcmIncomingConnectionObserver
+// CNATFWTurnConnectionHandler::IncomingMessageL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::IncomingMessageL(
+    TUint aStreamId,
+    const TDesC8& aMessage,
+    const TInetAddr& /*aLocalAddr*/,
+#ifdef _DEBUG
+    const TInetAddr& aFromAddr,
+    const TInetAddr& aPeerAddr,
+#else
+    const TInetAddr& /*aFromAddr*/,
+    const TInetAddr& /*aPeerAddr*/,
+#endif
+    TBool& aConsumed )
+    {
+    __TURNPLUGIN_ADDRLOG(
+        "CNATFWTurnConnectionHandler::IncomingMessageL FROMADDR", aFromAddr )
+    __TURNPLUGIN_ADDRLOG(
+        "CNATFWTurnConnectionHandler::IncomingMessageL PEERADDR", aPeerAddr )
+    
+    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 ) )
+        {
+        __TURNPLUGIN( "CNATFWTurnConnectionHandler::IncomingMessageL\
+        HandleDataL method to be called" )
+        
+        TBool consumed( EFalse );
+        TConnectionData* connection = ConnectionByIndex( streamInd, connInd );
+        
+        if ( connection->iTurnBinding )
+            {
+            if ( indicationData )
+                {
+                connection->iTurnBinding->HandleDataL( *indicationData,
+                    consumed, peerAddrFromIndication );
+                }
+            else
+                {
+                indicationData = connection->iTurnBinding->HandleDataL(
+                    aMessage, consumed, peerAddrFromIndication );
+                }
+            }
+        
+        if ( consumed )
+            {
+            consumingBindingInd = connInd;
+            aConsumed = ETrue;
+            }
+        
+        connInd--;
+        }
+    
+    delete indicationData;
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNcmOutgoingConnectionObserver
+// CNATFWTurnConnectionHandler::OutgoingMessageL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::OutgoingMessageL(
+    TUint aStreamId,
+    TUint aConnectionId,
+    const TInetAddr& aPeerAddr,
+    const TDesC8& aMessage,
+    TBool& aConsumed )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::OutgoingMessageL" )
+    
+    aConsumed = EFalse;
+    
+    TBool controlMsgDetected( EFalse );
+    TRAPD( err, controlMsgDetected = IsRequestOrIndicationL( aMessage ) )
+    
+    if ( !controlMsgDetected || err ) // Prevent loopback in msg handling
+        {        
+        TInt streamInd( IndexByStreamId( aStreamId ) );
+        TConnectionData* connection( NULL );
+        
+        if ( KErrNotFound != streamInd )
+            {
+            connection = ConnectionById( streamInd, aConnectionId );
+            }
+        
+        if ( connection )
+            {
+            aConsumed = ETrue;
+            
+            if ( aPeerAddr.IsUnspecified() )
+                {
+                if ( TConnectionData::EActDestNoneSet == connection->
+                    iActDestState || TConnectionData::EActDestTransitioning ==
+                    connection->iActDestState )
+                    {
+                    __TURNPLUGIN( "CNATFWTurnConnectionHandler::\
+                    OutgoingMessageL  Media will be sent in indication" )
+                    
+                    connection->iTurnBinding->SendIndicationL( connection->
+                        iPeerAddr, aMessage, EFalse );
+                    }
+                else
+                    {
+                    __TURNPLUGIN( "CNATFWTurnConnectionHandler::\
+                    OutgoingMessageL  Media will be sent directly" )
+                    
+                    if ( KProtocolInetTcp == iStreamArray[streamInd].
+                        iTransportProtocol )
+                        {
+                        CNATFWUNSAFTcpRelayPacket* packet =
+                            CNATFWUNSAFTcpRelayPacket::NewLC( aMessage,
+                                CNATFWUNSAFTcpRelayPacket::EFrameTypeData);
+                        
+                        CBufBase* message = packet->EncodeL();
+                        CleanupStack::PopAndDestroy( packet );
+                        
+                        CleanupStack::PushL( message );
+                        iConnMux->SendL( aStreamId, connection->iConnectionId,
+                            message->Ptr(0), ETrue );
+                        CleanupStack::PopAndDestroy( message );
+                        }
+                    else
+                        {
+                        iConnMux->SendL( aStreamId, connection->iConnectionId,
+                            aMessage, ETrue );
+                        }
+                    }
+                }
+            else
+                {
+                // Must be protocol message, send in indication(TURNbis-03, 4)
+                __TURNPLUGIN( "CNATFWTurnConnectionHandler::\
+                    OutgoingMessageL  PROTOCOL MSG will be sent" )
+                __TURNPLUGIN_ADDRLOG( 
+                    "CNATFWTurnConnectionHandler::OutgoingMessageL PEERADDR",
+                    aPeerAddr )
+                connection->iTurnBinding->SendIndicationL( aPeerAddr,
+                    aMessage, EFalse );
+                }
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNcmMessageObserver
+// CNATFWTurnConnectionHandler::IncomingMessageNotify
+// ---------------------------------------------------------------------------
+//
+HBufC8* CNATFWTurnConnectionHandler::IncomingMessageNotify(
+    TUint aStreamId,
+    const TDesC8& aMessage,
+    const TInetAddr& aLocalAddr,
+    const TInetAddr& aFromAddr,
+    TInetAddr& aPeerAddr )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::IncomingMessageNotify" )
+    
+    HBufC8* modifiedMessage( NULL );
+    TRAPD( error, modifiedMessage = HandleIncomingMessageL( 
+        aStreamId, aMessage, aLocalAddr, aFromAddr, aPeerAddr ) )
+    if ( KErrNone == error )
+        {
+        return modifiedMessage;
+        }
+    else
+        {
+        __TURNPLUGIN_INT1(
+            "CNATFWTurnConnectionHandler::IncomingMessageNotify ERR", error )
+        
+        return NULL;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNcmMessageObserver
+// CNATFWTurnConnectionHandler::OutgoingMessageNotify
+// ---------------------------------------------------------------------------
+//
+HBufC8* CNATFWTurnConnectionHandler::OutgoingMessageNotify(
+    TUint /*aStreamId*/,
+    TUint /*aConnectionId*/,
+    const TInetAddr& /*aDestinationAddress*/,
+    const TDesC8& /*aMessage*/ )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::OutgoingMessageNotify" )
+    
+    return NULL;
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNcmConnectionObserver
+// CNATFWTurnConnectionHandler::ConnectionNotify
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::ConnectionNotify(
+    TUint aStreamId,
+    TUint aConnectionId,
+    TConnectionNotifyType aType,
+    TInt aError )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::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(
+                    TTurnPluginCallbackInfo::EFetchingEnd, aStreamId,
+                        errcode, NULL ) )
+                }
+            else
+                {
+                TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                    TTurnPluginCallbackInfo::EError, aStreamId,
+                        aError, NULL ) )
+                }
+            
+            // Remove failed entry from array
+            DeleteStream( streamInd, ETrue );
+            }
+        else
+            {
+            switch ( aType )
+                {
+                case ESendingActivated:
+                    {
+                    connection->iSendingActivated = ETrue;
+                    
+                    if ( !connection->iTurnBinding )
+                        {
+                        TRAP_IGNORE( CreateTURNBindingL( aStreamId,
+                            aConnectionId ) )
+                        }
+                    }
+                    break;
+                
+                case EReceivingActivated:
+                    {
+                    connection->iReceivingActivated = ETrue;
+                    
+                    if ( connection->iLocalCandidate )
+                        {
+                        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                            TTurnPluginCallbackInfo::EActiveReceiving,
+                                aStreamId, KErrNone, NULL ) )
+                        }
+                    }
+                    break;
+                
+                case ESendingDeactivated:
+                    {
+                    connection->iSendingActivated = EFalse;
+                    }
+                    break;
+                
+                case EReceivingDeactivated:
+                    {
+                    connection->iReceivingActivated = EFalse;
+                    
+                    if ( connection->iLocalCandidate )
+                        {
+                        TRAP_IGNORE( iAsyncCallback->MakeCallbackL(
+                            TTurnPluginCallbackInfo::EDeactiveReceiving,
+                                aStreamId, KErrNone, NULL ) )
+                        }
+                    }
+                    break;
+                
+                case EConnectionRemoved:
+                    {
+                    DeleteStream( streamInd, EFalse );
+                    }
+                    break;
+                }
+            }
+        }
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::ConnectionNotify end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNATFWRefreshObserver
+// CNATFWTurnConnectionHandler::BindingRefreshL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::BindingRefreshL()
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::BindingRefreshL start" )
+    
+    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 );
+            connection->iTurnBinding->AllocateRequestL(
+                iStreamArray[streamInd].iRtoValue );
+            }
+        }
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::BindingRefreshL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// from base class MNATFWTimerObserver
+// CNATFWTurnConnectionHandler::TimerTriggeredL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::TimerTriggeredL( TUint aStreamId,
+                                                   TUint aConnectionId )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::TimerTriggeredL start" )
+    
+    TInt streamInd( IndexByStreamId( aStreamId ) );
+    TConnectionData* connection( NULL );
+    
+    if ( KErrNotFound != streamInd )
+        {
+        connection = ConnectionById( streamInd, aConnectionId );
+        }
+    
+    if ( connection )
+        {
+        if ( TConnectionData::EActDestTransitioning == connection->
+            iActDestState )
+            {
+            // Once the timer fires, if the REMOTE-ADDRESS was not absent
+            // from the Set Active Destination request which caused the
+            // client to start the timer, the client moves back to the
+            // "Set" state, and then updates the value of the active
+            // destination to the value of REMOTE-ADDRESS.
+            
+            if ( !connection->iPeerAddr.IsUnspecified() )
+                {
+                // Plug-in's client changed Active Destination on
+                // server successfully.
+                
+                connection->iActDestState = TConnectionData::EActDestSet;
+                connection->iCurrentActDest.SetAddress( connection->iPeerAddr.
+                    Address() );
+                connection->iCurrentActDest.SetPort( connection->iPeerAddr.
+                    Port() );
+                
+                iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                    EActiveSending, iStreamArray[streamInd].iStreamId,
+                        KErrNone, NULL );
+                }
+            else
+            // If REMOTE-ADDRESS was absent, the client sets the Active
+            // Destination to null and enders the "None Set" state.
+                {
+                // Plug-in's client resetted Active Destination on
+                // server successfully.
+                
+                connection->iActDestState = TConnectionData::EActDestNoneSet;
+                connection->iCurrentActDest = KAFUnspec;
+                
+                iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                    EDeactiveSending, iStreamArray[streamInd].iStreamId,
+                        KErrNone, NULL );
+                }
+            }
+        else if ( TConnectionData::EActDestNoneSet == connection->
+            iActDestState )
+            {
+            if ( !connection->iActDestAlreadySetOnServer )
+                {
+                connection->iActDestState = TConnectionData::EActDestSet;
+                connection->iCurrentActDest.SetAddress( connection->iPeerAddr.
+                    Address() );
+                connection->iCurrentActDest.SetPort( connection->iPeerAddr.
+                    Port() );
+                }
+            else
+                {
+                connection->iActDestAlreadySetOnServer = EFalse;
+                
+                // Active Destination was reset on server so now
+                // try to set Active Destination to remote address.
+                connection->iTurnBinding->SetActiveDestinationRequestL(
+                    connection->iPeerAddr, connection->iTimerValue );
+                }
+            }
+        else
+            {
+            if ( !connection->iActDestReqResent )
+                {
+                // As server was on "transitioning" state for the first
+                // Set Active Destination Request, a new request will
+                // be sent only once.
+                connection->iActDestReqResent = ETrue;
+                
+                connection->iTurnBinding->SetActiveDestinationRequestL(
+                    connection->iPeerAddr, connection->iTimerValue );
+                }
+            else
+                {
+                iAsyncCallback->MakeCallbackL( TTurnPluginCallbackInfo::
+                    EActiveSending, aStreamId, KErrNotReady, NULL );
+                }
+            }
+        }
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::TimerTriggeredL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::DeleteStream
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::DeleteStream( TUint aStreamInd, 
+    TBool aRemoveMuxConn )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::DeleteStream, start" )
+    ASSERT( aStreamInd < TUint( iStreamArray.Count() ) );
+    
+    TRAP_IGNORE(
+        iConnMux->UnregisterConnectionObserverL(
+            iStreamArray[aStreamInd].iStreamId, *this ) )
+    
+    TRAP_IGNORE(
+        iConnMux->UnregisterIncomingConnectionObserverL(
+            iStreamArray[aStreamInd].iStreamId, *this ) )
+    
+    TRAP_IGNORE(
+        iConnMux->UnregisterOutgoingConnectionObserverL(
+            iStreamArray[aStreamInd].iStreamId, *this ) )
+    
+    TRAP_IGNORE(
+        iConnMux->UnregisterMessageObserverL(
+            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->iTurnBinding )
+            {
+            connection->iTurnBinding->CancelRequest();
+            
+            delete connection->iTurnBinding;
+            connection->iTurnBinding = 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 );
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::DeleteStream, end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::FindConnection
+// Function expects that system does not have multiple TURN-connections bound
+// to the same local address and stream.
+// ---------------------------------------------------------------------------
+//
+TConnectionData* CNATFWTurnConnectionHandler::FindConnection(
+    TUint aStreamId,
+    const TInetAddr& aLocalAddr )
+    {
+    // find stream index
+    TInt foundStreamInd( KErrNotFound );
+    TInt streamInd( iStreamArray.Count() - 1 );
+    while ( KErrNotFound == foundStreamInd && 0 <= streamInd )
+        {
+        if ( iStreamArray[streamInd].iStreamId == aStreamId )
+            {
+            foundStreamInd = streamInd;
+            }
+        
+        streamInd--;
+        }
+    
+    TInt foundConnectionInd( KErrNotFound );
+    if ( KErrNotFound != foundStreamInd )
+        {
+        // find connection inside stream
+        const RArray<TConnectionData>& connArray( 
+            iStreamArray[foundStreamInd].iConnArray );
+        TInt connectionInd( connArray.Count() - 1 );
+        
+        while ( KErrNotFound == foundConnectionInd && 0 <= connectionInd )
+            {
+            const TInetAddr& localAddr( connArray[connectionInd].iLocalAddr );
+            
+            if ( MatchAddresses( localAddr, aLocalAddr ) )
+                {
+                foundConnectionInd = connectionInd;
+                }
+            
+            connectionInd--;
+            }
+        }
+    
+    if ( ( KErrNotFound != foundStreamInd ) && 
+         ( KErrNotFound != foundConnectionInd ) )
+        {
+        return &(iStreamArray[foundStreamInd].iConnArray[foundConnectionInd]);
+        }
+    else
+        {
+        return NULL;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::HandleIncomingMessageL
+// ---------------------------------------------------------------------------
+//
+HBufC8* CNATFWTurnConnectionHandler::HandleIncomingMessageL(
+    TUint aStreamId,
+    const TDesC8& aMessage,
+    const TInetAddr& aLocalAddr,
+    const TInetAddr& aFromAddr,
+    TInetAddr& aPeerAddr )
+    {
+    CNATFWUNSAFMessageFactory* decoder = CNATFWUNSAFMessageFactory::NewLC();
+    CNATFWUNSAFMessage* msg( NULL );
+    TRAPD( error, msg = decoder->DecodeL( aMessage ) )
+    CleanupStack::PopAndDestroy( decoder );
+    CleanupStack::PushL( msg );
+    
+    if ( error || NULL == msg )
+        {
+        // Not STUN message, must be media
+        TConnectionData* activeConnection( NULL );
+        TInt streamInd( iStreamArray.Count() - 1 );
+        
+        while ( !activeConnection && 0 <= streamInd )
+            {
+            TInt connInd = iStreamArray[streamInd].iConnArray.Count() - 1;
+            
+            while ( !activeConnection && 0 <= connInd )
+                {
+                activeConnection = ConnectionByIndex( streamInd, connInd );
+                
+                if ( TConnectionData::EActDestSet != activeConnection->
+                    iActDestState )
+                    {
+                    activeConnection = NULL;
+                    }
+                
+                connInd--;
+                }
+            
+            streamInd--;
+            }
+        
+        if ( activeConnection )
+            {
+            aPeerAddr = activeConnection->iCurrentActDest;
+            }
+        else
+            {
+            aPeerAddr = aFromAddr;
+            }
+        
+        CleanupStack::PopAndDestroy( msg );
+        return NULL;
+        }
+    
+    if ( msg->Type() == CNATFWUNSAFMessage::EDataIndication )
+        {
+        // Must be data from peer, either protocol message or media
+        // from nonactivated peer address
+        CNATFWUNSAFRemoteAddressAttribute* remoteAddress =
+            static_cast<CNATFWUNSAFRemoteAddressAttribute*>
+            ( msg->Attribute( CNATFWUNSAFAttribute::ERemoteAddress ) );
+        
+        if ( remoteAddress )
+            {
+            aPeerAddr = remoteAddress->Address();
+            __TURNPLUGIN_ADDRLOG( 
+               "CNATFWTurnConnectionHandler::HandleIncomingMessageL DATAIND",
+               aPeerAddr )
+            }
+        else
+            {
+            __TURNPLUGIN( 
+                "CNATFWTurnConnectionHandler::HandleIncomingMessageL, \
+                NO REMOTE ADDR FIELD" )
+            }
+        
+        const TDesC8& data = static_cast<CNATFWUNSAFDataAttribute*>(
+            msg->Attribute( CNATFWUNSAFAttribute::EData ) )->Value();
+        
+        HBufC8* modifiedMsg = data.AllocL();
+        CleanupStack::PopAndDestroy( msg );
+        return modifiedMsg;
+        }
+    else
+        {
+        // This is either response from physical TURN-server or STUN-data from
+        // peer address which is set as active destination.
+        TConnectionData* activeConnection 
+            = FindConnection( aStreamId, aLocalAddr );
+        
+        if ( activeConnection && 
+                !activeConnection->iCurrentActDest.IsUnspecified() )
+            {
+            aPeerAddr = activeConnection->iCurrentActDest;
+            }
+        else
+            {
+            aPeerAddr = aFromAddr;
+            }
+        
+        __TURNPLUGIN_ADDRLOG( 
+            "CNATFWTurnConnectionHandler::HandleIncomingMessageL NOT DATAIND",
+            aPeerAddr )
+        
+        CleanupStack::PopAndDestroy( msg );
+        return NULL;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::IndexByStreamId
+// ---------------------------------------------------------------------------
+//
+TInt CNATFWTurnConnectionHandler::IndexByStreamId( TUint aStreamId )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::IndexByStreamId" )
+    
+    TInt index( iStreamArray.Count() - 1 );
+    
+    while ( 0 <= index )
+        {
+        if ( aStreamId == iStreamArray[index].iStreamId )
+            {
+            return index;
+            }
+        
+        index--;
+        }
+
+    return KErrNotFound;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::ConnectionById
+// ---------------------------------------------------------------------------
+//
+TConnectionData* CNATFWTurnConnectionHandler::ConnectionById(
+    TUint aStreamInd,
+    TUint aConnectionId )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::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;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::ConnectionByIndex
+// ---------------------------------------------------------------------------
+//
+TConnectionData* CNATFWTurnConnectionHandler::ConnectionByIndex(
+    TUint aStreamInd,
+    TUint aConnectionInd )
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::ConnectionByIndex" )
+    
+    return &iStreamArray[aStreamInd].iConnArray[aConnectionInd];
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::GenerateServerListL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::GenerateServerListL()
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::GenerateServerListL start" )
+    
+    RPointerArray<MNATFWServerSettings> serverArray;
+    iTurnSettings->GetTurnServerArrayL( serverArray );
+    CleanupClosePushL( serverArray );
+    TInt count( serverArray.Count() );
+    
+    HBufC8* serverAddress =
+        iTurnSettings->LatestConnectedServerAddr().AllocLC();
+    TUint latestPort = iTurnSettings->LatestConnectedServerPort();
+    
+    // Add Latest connected server
+    if ( serverAddress->Compare( KNullDesC8 ) )
+        {
+        CTurnServerSettings* settings = CTurnServerSettings::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;
+                }
+            }
+            
+        if ( settings->Address().Compare( KNullDesC8 ) )
+            {
+            __TURNPLUGIN( "CNATFWStunConnectionHandler::GenerateServerListL\
+            - provisioned server added" )
+            }
+            
+        iServerList.AppendL( settings );
+        CleanupStack::Pop( settings );
+        }
+    
+    CleanupStack::PopAndDestroy( serverAddress );
+    
+    // Add provisioned servers
+    for ( TInt index( 0 ); index < count; index++ )
+        {
+        CTurnServerSettings* settings = CTurnServerSettings::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() );
+            }
+        
+        iServerList.AppendL( settings );
+        CleanupStack::Pop( settings );
+        }
+    
+    // Domain
+    CTurnServerSettings* settings = CTurnServerSettings::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 );
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::GenerateServerListL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWStunConnectionHandler::TryNextServerL
+// ---------------------------------------------------------------------------
+//
+void CNATFWTurnConnectionHandler::TryNextServerL()
+    {
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::TryNextServerL start" )
+    
+    delete iStunClient;
+    iStunClient = NULL;
+    
+    if ( iServerIndex < iServerList.Count() )
+        {
+        TInt index( iServerIndex );
+        iServerIndex++;
+        
+        TInt refresh( iNatSettings->RefreshIntervalUdp() );
+        iTurnRefreshInterval = ( refresh ) ? ( refresh * KMicrosecFactor ) :
+            KDefaultRefreshInterval;
+        
+        TInt retransmitInterval( iTurnSettings->RetransmissionTimeout() );
+        
+        TUint port = iServerList[index]->Port() ? iServerList[index]->Port() :
+            KDefaultStunSrvPort;
+        
+        iStunClient = CSTUNClient::NewL( retransmitInterval,
+                                         iServerList[index]->Address(),
+                                         port,
+                                         KStunRelay,
+                                         iSocketServ,
+                                         iConnection,
+                                         *iTimerServ,
+                                         *this,
+                                         ETrue,
+                                         EFalse,
+                                         EFalse,
+                                         iConnMux );
+        
+        if ( iServerList[index]->Username() && iServerList[index]->
+            Password() )
+            {
+            TRAP_IGNORE( iStunClient->SetCredentialsL( *iServerList[index]->
+                Username(), *iServerList[index]->Password() ) )
+            }
+        }
+    else
+        {
+        User::Leave( KErrNotFound );
+        }
+    
+    __TURNPLUGIN( "CNATFWTurnConnectionHandler::TryNextServerL end" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWTurnConnectionHandler::MatchAddresses
+// ---------------------------------------------------------------------------
+//
+TBool CNATFWTurnConnectionHandler::MatchAddresses( const TInetAddr& aAddr1,
+    const TInetAddr& aAddr2 )
+    {
+    // 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