natfw/natfwstunturnclient/src/cstunclientimplementation.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwstunturnclient/src/cstunclientimplementation.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1346 @@
+/*
+* Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    
+*
+*/
+
+
+
+
+#include "natfwunsafserverresolver.h"
+#include "natfwunsafserverresolverobserver.h"
+#include "cnatfwunsaficmpreceiver.h"
+#include "natfwunsaflog.h"
+#include "casynccallback.h"
+#include "stunassert.h"
+#include "cstunclientimplementation.h"
+#include "cstunclientresolvingtcp.h"
+#include "cstunclientresolvingtls.h"
+#include "cstunclientresolvingudp.h"
+#include "cstunclientgetsharedsecret.h"
+#include "cstunclientready.h"
+#include "cstunclientrenewsharedsecret.h"
+#include "natfwstunbinding.h"
+#include "cstunbindingimplementation.h"
+#include "ctransactionidgenerator.h"
+#include "cstunsharedsecret.h"
+#include "cstuncredentials.h"
+#include "cstuncredentials.h"
+
+_LIT8( KUdp, "udp" );
+_LIT8( KTcp, "tcp" );
+_LIT8( KTls, "tls" );
+const TUint KTlsPort = 443;
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::NewL
+// ---------------------------------------------------------------------------
+//
+CSTUNClientImplementation*
+CSTUNClientImplementation::NewL( CSTUNClient& aClient,
+                                 TInt aRetransmitInterval,
+                                 const TDesC8& aServerAddress,
+                                 TUint aServerPort,
+                                 const TDesC8& aServiceName,
+                                 RSocketServ& aSocketServ,
+                                 RConnection& aConnection,
+                                 CDeltaTimer& aTimer,
+                                 MSTUNClientObserver& aObserver,
+                                 TBool aObtainSharedSecret,
+                                 TBool aFailIfNoSRVRecordsFound,
+                                 TBool aIcmpReceiverUsed,
+                                 MNcmConnectionMultiplexer* aMultiplexer,
+                                 TTransportProtocol aTransportProtocol )
+    {
+    CSTUNClientImplementation* self =
+        new ( ELeave ) CSTUNClientImplementation( aClient,
+                                                  aRetransmitInterval,
+                                                  aServerPort,
+                                                  aSocketServ,
+                                                  aConnection,
+                                                  aTimer,
+                                                  aObserver,
+                                                  aObtainSharedSecret,
+                                                  aMultiplexer,
+                                                  aTransportProtocol );
+    CleanupStack::PushL( self );
+    self->ConstructL( aServerAddress, aServiceName, 
+                      aFailIfNoSRVRecordsFound, aIcmpReceiverUsed );
+    CleanupStack::Pop( self );
+    return self;    
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::NewL - overloaded for ICE conn check usage
+// ---------------------------------------------------------------------------
+//
+CSTUNClientImplementation*
+CSTUNClientImplementation::NewL( CSTUNClient& aClient,
+                                 TInt aRetransmitInterval,
+                                 CDeltaTimer& aTimer,
+                                 MSTUNClientObserver& aObserver,
+                                 MNcmConnectionMultiplexer* aMultiplexer,
+                                 TTransportProtocol aTransportProtocol )
+    {
+    CSTUNClientImplementation* self =
+        new ( ELeave ) CSTUNClientImplementation( aClient,
+                                                  aRetransmitInterval,
+                                                  aTimer,
+                                                  aObserver,
+                                                  aMultiplexer,
+                                                  aTransportProtocol );
+    CleanupStack::PushL( self );
+    self->ConstructL( );
+    CleanupStack::Pop( self );
+    return self;    
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::CSTUNClientImplementation
+// ---------------------------------------------------------------------------
+//
+CSTUNClientImplementation::CSTUNClientImplementation(
+    CSTUNClient& aClient,
+    TInt aRetransmitInterval,
+    TUint aServerPort,
+    RSocketServ& aSocketServ,
+    RConnection& aConnection,
+    CDeltaTimer& aTimer,
+    MSTUNClientObserver& aObserver,
+    TBool aObtainSharedSecret,
+    MNcmConnectionMultiplexer* aMultiplexer,
+    TTransportProtocol aTransportProtocol ) :
+    CSTUNTimerUser( aTimer ),
+    iClient( aClient ),
+    iRetransmitInterval( aRetransmitInterval ),
+    iServerPort( aServerPort ? aServerPort : EDefaultSTUNPort ),
+    iSocketServer( aSocketServ ),
+    iConnection( aConnection ),    
+    iObserver( aObserver ),
+    iObtainSharedSecret( aObtainSharedSecret ),
+    iMultiplexer( aMultiplexer ),
+    iTransportProtocol( aTransportProtocol )
+#ifdef TEST_EUNIT
+    , iTcpAddresses( 1 ),
+    iUdpAddresses( 1 )
+#endif
+    {    
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::CSTUNClientImplementation - overloaded
+// ---------------------------------------------------------------------------
+//
+CSTUNClientImplementation::CSTUNClientImplementation(
+    CSTUNClient& aClient,
+    TInt aRetransmitInterval,
+    CDeltaTimer& aTimer,
+    MSTUNClientObserver& aObserver,
+    MNcmConnectionMultiplexer* aMultiplexer,
+    TTransportProtocol aTransportProtocol ) :
+    CSTUNTimerUser( aTimer ),
+    iClient( aClient ),
+    iRetransmitInterval( aRetransmitInterval ),
+    iSocketServer( *( RSocketServ* )0x1 ),
+    iConnection( *( RConnection* )0x1 ),
+    iObserver( aObserver ),
+    iMultiplexer( aMultiplexer ),
+    iTransportProtocol( aTransportProtocol )
+    {
+    }
+        
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::CSTUNClientImplementation
+// Dummy implementation. Default constructor is declared private and not used.
+// ---------------------------------------------------------------------------
+//
+CSTUNClientImplementation::CSTUNClientImplementation() :
+    CSTUNTimerUser( *( CDeltaTimer* )0x1 ),        
+    iClient( *( CSTUNClient* )0x1 ),
+    iSocketServer( *( RSocketServ* )0x1 ),
+    iConnection( *( RConnection* )0x1 ),
+    iObserver( *( MSTUNClientObserver* )0x1 )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::CSTUNClientImplementation
+// Dummy implementation. Copy constructor is declared private and not used.
+// ---------------------------------------------------------------------------
+//
+CSTUNClientImplementation::CSTUNClientImplementation(
+    const CSTUNClientImplementation& aImplementation ) :
+    CSTUNTimerUser( *( CDeltaTimer* )0x1 ),
+    iClient( aImplementation.iClient ),
+    iSocketServer( aImplementation.iSocketServer ),
+    iConnection( aImplementation.iConnection ),
+    iObserver( aImplementation.iObserver )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ConstructL( const TDesC8& aServerAddress,
+                                            const TDesC8& aServiceName,
+                                            TBool aFailIfNoSRVRecordsFound,
+                                            TBool aIcmpReceiverUsed )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ConstructL IN" )
+    __ASSERT_ALWAYS( aServerAddress.Length() > 0, 
+        User::Leave( KErrArgument ) );
+    
+    __STUNTURNCLIENT_STR8( "CSTUNClientImplementation stunserver=",
+        aServerAddress )
+    iServerAddress = aServerAddress.AllocL();
+    
+    __STUNTURNCLIENT_STR8( "CSTUNClientImplementation servicename=",
+        aServiceName )
+    
+    iServiceName = aServiceName.AllocL();
+    iAsyncCallback = CAsyncCallback::NewL( iObserver );
+        
+    iResolver = CNATFWUNSAFServerResolver::NewL( iSocketServer,
+                                                 iConnection,
+                                                 *this,
+                                                 aFailIfNoSRVRecordsFound );
+                                                 
+    iTransactionIDGenerator = CTransactionIDGenerator::NewL();
+    
+    if ( aIcmpReceiverUsed )
+        {
+        iIcmpReceiver = CIcmpReceiver::NewL( *this, iSocketServer );
+        }
+    
+    iRenewSharedSecret = new ( ELeave ) CSTUNClientRenewSharedSecret;
+    iReady = new ( ELeave ) CSTUNClientReady( *iRenewSharedSecret );
+    iGetSharedSecret = new ( ELeave ) CSTUNClientGetSharedSecret( *iReady );
+    iResolvingUDP = new ( ELeave ) CSTUNClientResolvingUDP( *iGetSharedSecret,
+                                                            *iReady );
+    if ( iObtainSharedSecret )
+        {
+        iResolvingTLS = new ( ELeave ) 
+            CSTUNClientResolvingTLS( *iResolvingUDP );
+        iResolvingTCP = new ( ELeave ) 
+            CSTUNClientResolvingTCP( *iResolvingTLS, *iResolvingUDP );
+        }
+    else
+        {
+        iResolvingTCP = new ( ELeave )
+            CSTUNClientResolvingTCP( *iResolvingUDP );
+        }
+    
+    iRenewSharedSecret->SetNeighbourStates( *iReady );
+
+    if ( iServiceName->Compare( KStunRelay ) == 0 && iObtainSharedSecret )
+        {
+        ChangeState( iResolvingTLS );
+        ResolveAddressL( KTls, iTcpAddresses, KTlsPort, KStunRelay );
+        }
+    
+    else if ( iObtainSharedSecret )
+        {
+        ChangeState( iResolvingTCP );
+        ResolveAddressL( KTcp, iTcpAddresses, iServerPort, *iServiceName );
+        }
+    
+    else
+        {
+        ChangeState( iResolvingUDP );
+        ResolveUdpL();
+        }
+        
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ConstructL OUT" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ConstructL - overloaded for ICE conn check usage
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ConstructL( )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ConstructL for ICE" )
+
+    TInetAddr defaultAddr;
+    defaultAddr.SetAddress( KInetAddrAll );
+    
+    // Make state machine work with hack
+    iUdpAddresses.AppendL( defaultAddr );
+    iObtainSharedSecret = EFalse;
+    iAsyncCallback = CAsyncCallback::NewL( iObserver );
+        
+    iTransactionIDGenerator = CTransactionIDGenerator::NewL();
+    
+    iRenewSharedSecret = new ( ELeave ) CSTUNClientRenewSharedSecret;
+    iReady = new ( ELeave ) CSTUNClientReady( *iRenewSharedSecret );
+    iGetSharedSecret = new ( ELeave ) CSTUNClientGetSharedSecret( *iReady );
+    iResolvingUDP = new ( ELeave ) CSTUNClientResolvingUDP( *iGetSharedSecret,
+                                                            *iReady );
+    iResolvingTCP = new ( ELeave ) CSTUNClientResolvingTCP( *iResolvingUDP );
+    
+    iRenewSharedSecret->SetNeighbourStates( *iReady );
+    ChangeState( iReady );
+    // do not send notify, act as syncronous
+    }
+
+    
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::~CSTUNClientImplementation
+// ---------------------------------------------------------------------------
+//
+CSTUNClientImplementation::~CSTUNClientImplementation()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::~CSTUNClientImplementation" )
+    TInt count( iBindings.Count() );
+    if ( count > 0 )
+        {
+        for ( TInt i = 0; i < count; ++i ) // check that ++i
+            {        
+            iBindings[i]->Implementation().DetachClient();
+            }
+        }
+    iBindings.Close();    
+
+    FreeResolverResources();
+
+    delete iAsyncCallback;
+    delete iResolvingTLS;
+    delete iResolvingTCP;
+    delete iResolvingUDP;
+    delete iGetSharedSecret;
+    delete iReady;
+    delete iRenewSharedSecret;
+
+    delete iTransactionIDGenerator;
+    delete iSharedSecret;
+    delete iCredentials;
+    delete iIcmpReceiver;
+    
+    delete iTimer;
+    delete iServiceName;
+
+    iTcpAddresses.Close();
+    iUdpAddresses.Close();
+    delete iServerAddress;
+    iMultiplexer = NULL;
+    iState = NULL;
+    
+    __STUNTURNCLIENT( "CSTUNClientImplementation::\
+    ~CSTUNClientImplementation end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::CompletedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::CompletedL()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::CompletedL" )
+    __TEST_INVARIANT;
+
+    if ( iState )
+        {
+        iState->ResolvingCompletedL( *this, iObtainSharedSecret );
+        }
+        
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::CompletedL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ErrorOccured
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ErrorOccured( TInt aError )
+    {
+    __STUNTURNCLIENT_INT1( "CSTUNClientImplementation::ErrorOccured: "
+        , aError )
+    __TEST_INVARIANT;
+
+    if ( iState )
+        {
+        if ( aError != KErrNoMemory )
+            {
+            aError = KErrNATFWDnsFailure;
+            }
+        iState->ResolvingFailed( *this, aError );
+        }
+        
+    __TEST_INVARIANT;    
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ErrorOccured end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::IcmpError
+// Don't compare aAddress to iUdpAddresses, as some binding may still have an
+// address that has been removed from iUdpAddresses if another binding called
+// ObtainServerAddress.
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::IcmpError( const TInetAddr& aAddress )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::IcmpError" )
+    __TEST_INVARIANT;
+
+    for ( TInt i = 0; i < iBindings.Count(); ++i )
+        {
+        iBindings[i]->Implementation().IcmpError( aAddress );
+        }
+    RemoveAddress( aAddress );
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::IcmpError end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::SharedSecretObtainedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::SharedSecretObtainedL()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::SharedSecretObtainedL" )
+    __TEST_INVARIANT;
+
+    if ( iState )
+        {        
+        iState->SharedSecretReceivedL( *this );
+        }
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::SharedSecretObtainedL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::SharedSecretErrorL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::SharedSecretErrorL( TInt aError )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::SharedSecretErrorL" )
+    __TEST_INVARIANT;
+    
+    if ( iState )
+        {
+        iState->SharedSecretErrorL( *this, aError );
+        }
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::SharedSecretErrorL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::STUNClient
+// ---------------------------------------------------------------------------
+//
+const CSTUNClient& CSTUNClientImplementation::STUNClient() const
+    {
+    __TEST_INVARIANT;
+
+    return iClient;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::TimerProvider
+// ---------------------------------------------------------------------------
+//
+CDeltaTimer& CSTUNClientImplementation::TimerProvider()
+    {
+    __TEST_INVARIANT;
+
+    return DeltaTimer();
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::RetransmitInterval
+// ---------------------------------------------------------------------------
+//
+TInt CSTUNClientImplementation::RetransmitInterval() const
+    {
+    __TEST_INVARIANT;
+
+    return iRetransmitInterval;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::TransportProtocol
+// ---------------------------------------------------------------------------
+//
+TTransportProtocol CSTUNClientImplementation::TransportProtocol() const
+    {
+    __TEST_INVARIANT;
+
+    return iTransportProtocol;
+    }
+    
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::AddressResolvedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::AddressResolvedL(
+    const CBinding& aBinding ) const
+    {
+    __TEST_INVARIANT;
+
+    iAsyncCallback->MakeCallbackL( TSTUNCallbackInfo::EEventAddressResolvedL,
+                                   &aBinding );
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ObtainSharedSecretL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ObtainSharedSecretL( CBinding& aBinding )
+    {
+    __TEST_INVARIANT;
+    __ASSERT_ALWAYS( iState != NULL, User::Leave( KErrServerTerminated ) );
+
+    iState->ObtainSharedSecretL( *this, aBinding );
+
+    __TEST_INVARIANT;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::SharedSecretRejectedL
+// ---------------------------------------------------------------------------
+//
+TBool
+CSTUNClientImplementation::SharedSecretRejectedL( const CBinding& aBinding,
+                                                  const TDesC8& aUsername,
+                                                  const TDesC8& aPassword )
+    {
+    __TEST_INVARIANT;
+
+    return iState && iState->SharedSecretRejectedL( *this,
+                                                    aBinding,
+                                                    aUsername,
+                                                    aPassword );        
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ObtainServerAddress
+// ---------------------------------------------------------------------------
+//
+TBool CSTUNClientImplementation::ObtainServerAddress( TInetAddr& aAddress )    
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ObtainServerAddress" )
+    __TEST_INVARIANT;
+    #ifdef _DEBUG_EUNIT
+        TInetAddr addr;
+        addr.SetAddress( INET_ADDR( 10,32,194,251 ) );
+        addr.SetFamily( KAfInet );
+        iUdpAddresses.Append( addr );
+    #endif
+
+    if ( !aAddress.IsUnspecified() )
+        {
+        // Binding has tried aAddress and found it doesn't respond.
+        RemoveAddress( aAddress );
+        }
+
+    if ( iUdpAddresses.Count() > 0 )
+        {
+        aAddress = iUdpAddresses[ 0 ];
+        return ETrue;
+        }
+
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ObtainServerAddress end" )
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ObtainTransactionIDL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ObtainTransactionIDL(
+    TNATFWUNSAFTransactionID& aTransactionID )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ObtainTransactionIDL" )
+    __TEST_INVARIANT;
+    #ifdef _DEBUG_EUNIT
+        aTransactionID.Append(TUint8(0));
+        aTransactionID.Append(TUint8(1));
+        aTransactionID.Append(TUint8(2));
+        aTransactionID.Append(TUint8(3));
+        aTransactionID.Append(TUint8(4));
+        aTransactionID.Append(TUint8(5));
+        aTransactionID.Append(TUint8(6));
+        aTransactionID.Append(TUint8(7));
+        aTransactionID.Append(TUint8(8));
+        aTransactionID.Append(TUint8(9));
+        aTransactionID.Append(TUint8(0xa));
+        aTransactionID.Append(TUint8(0xb));
+    #else
+        iTransactionIDGenerator->GetIDL( this, sizeof( *this ), aTransactionID );
+    #endif
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ObtainTransactionIDL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::AttachBindingL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::AttachBindingL( const CBinding& aBinding )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::AttachBindingL" )
+    __TEST_INVARIANT;
+
+    iBindings.AppendL( &aBinding );
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::AttachBindingL end" )
+    }
+                                     
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::DetachBinding
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::DetachBinding( const CBinding& aBinding )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::DetachBinding" )
+    __TEST_INVARIANT;
+
+    for ( TInt i = 0; i < iBindings.Count(); ++i )
+        {
+        if ( iBindings[ i ] == &aBinding )
+            {
+            iAsyncCallback->CancelCallback( *iBindings[i] );
+            iBindings.Remove( i );
+            __TEST_INVARIANT;
+            return;
+            }
+        }
+    __STUNTURNCLIENT( "CSTUNClientImplementation::DetachBinding end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::BindingErrorL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::BindingErrorL( const CBinding& aBinding,
+                                               TInt aError, TBool aIsFatal )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::BindingErrorL" )
+    __TEST_INVARIANT;
+    
+    if ( aIsFatal )
+        {
+        iAsyncCallback->MakeCallbackL( 
+            TSTUNCallbackInfo::EErrorOccurred, &aBinding, aError );
+        }
+    
+    else
+        {
+        TInt count( iBindings.Count() );
+        TInt index( KErrNotFound );
+        
+        for ( TInt i = 0; i < count; i++ )
+            {
+            if ( &aBinding == iBindings[i] )
+                {
+                index = i;
+                }
+            }
+        
+        switch ( aError )
+            {
+            case E401Unauthorized:
+                if ( index >= 0 )
+                    {
+                    if ( iBindings[index]->RealmFromResponse() )
+                        {
+                        // Client should set long term credentials
+                        iAsyncCallback->MakeCallbackL( 
+                            TSTUNCallbackInfo::EErrorOccurred, 
+                            &aBinding, aError );
+                        }
+                    else
+                        {
+                        RenewSharedSecretL();
+                        }
+                    }
+            
+            break;
+            
+            case E430StaleCredentials:
+            break;
+            
+            case E436UnknownUsername:
+                if ( iCredentials && iSharedSecret )
+                    {
+                    // FATAL ERROR
+                    iAsyncCallback->MakeCallbackL( 
+                        TSTUNCallbackInfo::EErrorOccurred, &aBinding, aError );
+                    }
+                else
+                    {
+                    RenewSharedSecretL();
+                    }
+            break;
+            
+            case E432MissingUsername:
+            break;
+            
+            case E433UseTLS:
+                if ( iCredentials || iSharedSecret )
+                    {
+                    // FATAL ERROR
+                    iAsyncCallback->MakeCallbackL( 
+                        TSTUNCallbackInfo::EErrorOccurred, &aBinding, aError );
+                    }
+                else
+                    {
+                    RenewSharedSecretL();
+                    }
+            break;
+            
+            case E434MissingRealm:
+                // client should decide if try again with credentials
+                iAsyncCallback->MakeCallbackL( 
+                    TSTUNCallbackInfo::EErrorOccurred, &aBinding, aError );
+            break;
+            
+            default:
+                // FATAL ERROR
+                iAsyncCallback->MakeCallbackL( 
+                    TSTUNCallbackInfo::EErrorOccurred, 
+                    &aBinding, KErrGeneral );
+            break;
+            }
+        }
+    
+    __STUNTURNCLIENT( "CSTUNClientImplementation::BindingErrorL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::BindingEventOccurred
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::BindingEventOccurred( 
+    const CBinding& aBinding, TSTUNCallbackInfo::TFunction aEvent )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::BindingEventOccurred" )
+    TRAP_IGNORE( iAsyncCallback->MakeCallbackL( aEvent,
+                                                &aBinding,
+                                                KErrNone ) );
+                                   
+    __STUNTURNCLIENT( "CSTUNClientImplementation::BindingEventOccurred exit" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::PassInitCompletedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::PassInitCompletedL( TInt aError ) const
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::PassInitCompletedL" )
+    __TEST_INVARIANT;
+
+    iAsyncCallback->MakeCallbackL( TSTUNCallbackInfo::EInitCompleted,
+                                   NULL,
+                                   aError,
+                                   &iClient );
+
+    __STUNTURNCLIENT( "CSTUNClientImplementation::PassInitCompletedL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::PassCredentialsRejectedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::PassCredentialsRejectedL(
+    const CBinding& aBinding ) const
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::PassCredentialsRejectedL" )
+    __TEST_INVARIANT;
+
+    iAsyncCallback->MakeCallbackL( TSTUNCallbackInfo::EEventCredentialsRejected,
+                                   &aBinding );
+    __STUNTURNCLIENT( "CSTUNClientImplementation::PassCredentialsRejectedL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::IsInitialized
+// ---------------------------------------------------------------------------
+//
+TBool CSTUNClientImplementation::IsInitialized() const
+    {
+    __TEST_INVARIANT;
+
+    return ( iState == iReady ) || ( iState == iRenewSharedSecret );
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::STUNServerAddrL
+// ---------------------------------------------------------------------------
+//
+const TInetAddr& CSTUNClientImplementation::STUNServerAddrL() const
+    {
+    __TEST_INVARIANT;
+    __ASSERT_ALWAYS( IsInitialized(), User::Leave( KErrNotReady ) );
+    __ASSERT_ALWAYS( iUdpAddresses.Count() > 0, User::Leave( KErrNotFound ) );
+
+    return iUdpAddresses[ 0 ];
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::SetCredentialsL
+// iCredentials and iSharedSecret can both exist at the same time.
+// ---------------------------------------------------------------------------
+//    
+void CSTUNClientImplementation::SetCredentialsL( const TDesC8& aUsername,
+                                                 const TDesC8& aPassword )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::SetCredentialsL in" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L( aUsername.Length(), KErrArgument );
+    __STUN_ASSERT_L( aPassword.Length(), KErrArgument );
+    
+    CSTUNCredentials* credentials = CSTUNCredentials::NewL( aUsername,
+                                                            aPassword );
+    delete iCredentials;
+    iCredentials = NULL;
+    iCredentials = credentials;
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::SetCredentialsL end" )
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNClientImplementation::SharedSecretObtained
+// -----------------------------------------------------------------------------
+//
+TBool CSTUNClientImplementation::SharedSecretObtained() const
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::SharedSecretObtained" )
+    return ( iSharedSecret && iSharedSecret->Username().Length() > 0 );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNClientImplementation::HasPresetCredentials
+// -----------------------------------------------------------------------------
+//
+TBool CSTUNClientImplementation::HasPresetCredentials() const
+    {
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::HasPresetCredentials" )
+    return iCredentials != NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNClientImplementation::ChangeState
+// -----------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ChangeState( const CSTUNClientState* aNewState )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ChangeState" )
+    __TEST_INVARIANT;
+
+    iState = aNewState;
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ChangeState end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::Terminate
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::Terminate( TInt aError )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::Terminate" )
+    __TEST_INVARIANT;
+    // Terminate only once    
+    __STUN_ASSERT_RETURN( iState != NULL, KErrDied );    
+    __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument );
+
+    NATFWUNSAF_INTLOG( "STUNClient terminated, reason", aError )
+
+    if ( !IsInitialized() )
+        {
+        TRAP_IGNORE( PassInitCompletedL( aError ) )
+        }
+    ChangeState( NULL );
+
+    // A terminating binding calls CSTUNClientImplementation::BindingErrorL
+    for ( TInt i = 0; i < iBindings.Count(); ++i )
+        {
+        iBindings[i]->Implementation().Terminate( aError );
+        }
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::Terminate end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::TcpResolvedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::TcpResolvedL( TBool aObtainSharedSecret )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::TcpResolvedL" )
+    __TEST_INVARIANT;
+
+    iObtainSharedSecret = aObtainSharedSecret;
+    
+    if ( iObtainSharedSecret )
+        {
+        ResolveAddressL( KTls, iTcpAddresses, KTlsPort, *iServiceName );
+        }
+    else
+        {
+        ResolveUdpL();
+        }
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::TcpResolvedL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::TlsResolvedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::TlsResolvedL( )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::TlsResolvedL" )
+
+    ResolveUdpL();
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::TlsResolvedL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::FreeResolverResources
+// Don't use __TEST_INVARIANT, as this function is used from destructor.
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::FreeResolverResources()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::FreeResolverResources" )
+    if ( iResolver )
+        {
+        iResolver->CancelResolving();
+        delete iResolver;
+        iResolver = NULL;
+        }
+    __STUNTURNCLIENT( "CSTUNClientImplementation::FreeResolverResources end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ResolveUdpL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ResolveUdpL()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ResolveUdpL" )
+    __TEST_INVARIANT;
+
+    ResolveAddressL( KUdp, iUdpAddresses );
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ResolveUdpL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ResolveAddressL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ResolveAddressL( const TDesC8& aProtocol,
+                                                 RArray<TInetAddr>& aResult )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ResolveAddressL" )
+    __TEST_INVARIANT;
+    
+    __STUNTURNCLIENT_STR8( "stunserveraddress: ", *iServerAddress )
+    __STUNTURNCLIENT_INT1( "stunserverport: ", iServerPort )
+    __STUNTURNCLIENT_STR8( "protocol: ", aProtocol )
+    
+    iResolver->ResolveL( *iServerAddress,
+                         *iServiceName,
+                         aProtocol,
+                         iServerPort,
+                         aResult );
+    
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ResolveAddressL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::ResolveAddressL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::ResolveAddressL( const TDesC8& aProtocol,
+                                                 RArray<TInetAddr>& aResult,
+                                                 TUint aPort,
+                                                 const TDesC8& aService )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ResolveAddressL" )
+    __TEST_INVARIANT;
+    
+    __STUNTURNCLIENT_STR8( "stunserveraddress: ", *iServerAddress )
+    __STUNTURNCLIENT_INT1( "stunserverport: ", iServerPort )
+    __STUNTURNCLIENT_STR8( "protocol: ", aProtocol )
+    __STUNTURNCLIENT_STR8( "service: ", aService )
+    
+    iResolver->ResolveL( *iServerAddress,
+                         aService,
+                         aProtocol,
+                         aPort,
+                         aResult );
+    
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::ResolveAddressL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::GetSharedSecretFromServerL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::GetSharedSecretFromServerL()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::\
+    GetSharedSecretFromServerL" )
+    __TEST_INVARIANT;
+
+    __ASSERT_ALWAYS( iTcpAddresses.Count() > 0, User::Leave( KErrNotFound ) );
+
+    delete iSharedSecret;
+    iSharedSecret = NULL;
+    
+    if ( iCredentials )
+        {
+        iSharedSecret = CSTUNSharedSecret::NewL( iSocketServer,
+                                             iConnection,
+                                             DeltaTimer(),
+                                             iTcpAddresses[0],
+                                             *iTransactionIDGenerator,
+                                             *this,
+                                             iCredentials->Username(),
+                                             iCredentials->Password() );
+        }
+    
+    else
+        {
+        iSharedSecret = CSTUNSharedSecret::NewL( iSocketServer,
+                                             iConnection,
+                                             DeltaTimer(),
+                                             iTcpAddresses[0],
+                                             *iTransactionIDGenerator,
+                                             *this,
+                                             KNullDesC8(),
+                                             KNullDesC8() );
+        }
+    
+    // Stop current shared secret's timer
+    StopTimer();
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::\
+    GetSharedSecretFromServerL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::PassSharedSecretToBindingL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::PassSharedSecretToBindingL(
+    CBinding& aBinding ) const
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::PassSharedSecretToBindingL" )
+    __TEST_INVARIANT;
+
+    const TDesC8* username = &KNullDesC8();
+    const TDesC8* password = &KNullDesC8();
+    
+    if ( iSharedSecret )
+        {
+        if ( iObtainSharedSecret )
+            {
+            username = &iSharedSecret->Username();
+            password = &iSharedSecret->Password();
+            }
+        }
+        
+    else if ( iCredentials )
+        {
+        username = &iCredentials->Username();
+        password = &iCredentials->Password();
+        }
+    else
+        {
+        // if ... else if chain end
+        }  
+    aBinding.Implementation().SharedSecretObtainedL( 
+        *username, *password );
+    
+    __STUNTURNCLIENT( "CSTUNClientImplementation::PassSharedSecretToBindingL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::TimerExpiredL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::TimerExpiredL()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::TimerExpiredL" )
+    __TEST_INVARIANT;
+
+    GetSharedSecretFromServerL();
+    ChangeState( iRenewSharedSecret );
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::TimerExpiredL end" )
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNClientImplementation::LeaveFromTimerExpired
+// -----------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::LeaveFromTimerExpired( TInt aError )
+    {
+    __STUNTURNCLIENT_INT1( "CSTUNClientImplementation::\
+    LeaveFromTimerExpired error:", aError )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument );
+
+    Terminate( aError );
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::StartSharedSecretTimer
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::StartSharedSecretTimer()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::StartSharedSecretTimer" )
+    __TEST_INVARIANT;
+
+    const TUint KSharedSecretValidTime = 540000; // 9 minutes
+    StartTimer( KSharedSecretValidTime );
+
+    __TEST_INVARIANT;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::MultiplexerInstance
+// ---------------------------------------------------------------------------
+//
+MNcmConnectionMultiplexer* 
+    CSTUNClientImplementation::MultiplexerInstance()
+    {
+    return iMultiplexer;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNClientImplementation::RenewSharedSecretL
+// -----------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::RenewSharedSecretL()
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::RenewSharedSecretL" )
+    if ( !iObtainSharedSecret )
+        {
+        delete iResolver;
+        iResolver = NULL;
+        iResolver = CNATFWUNSAFServerResolver::NewL( iSocketServer,
+                                                     iConnection,
+                                                     *this,
+                                                     ETrue );
+        iObtainSharedSecret = ETrue;
+        
+        __STUNTURNCLIENT_STR8( "servicename: ", *iServiceName )
+        
+        if ( !iResolvingTLS )
+            {
+            iResolvingTLS = new ( ELeave ) 
+                CSTUNClientResolvingTLS( *iResolvingUDP );
+            // must set state to ensure that TCP state is not current state
+            ChangeState( iResolvingTLS );
+            delete iResolvingTCP;
+            iResolvingTCP = NULL;
+            
+            iResolvingTCP = new ( ELeave ) 
+                CSTUNClientResolvingTCP( *iResolvingTLS, *iResolvingUDP );
+            }
+        
+        if ( iServiceName->Compare( KStunRelay ) == 0 )
+            {
+            ChangeState( iResolvingTLS );
+            ResolveAddressL( KTls, iTcpAddresses, KTlsPort, *iServiceName );
+            }
+        else
+            {
+            ChangeState( iResolvingTCP );
+            ResolveAddressL( KTcp, iTcpAddresses, iServerPort, *iServiceName );
+            }
+        }
+    
+    else
+        {
+        StopTimer();
+        __STUNTURNCLIENT( "timer stopped" )
+        TimerExpiredL();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::UsenameForIndication
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CSTUNClientImplementation::UsernameForIndication()
+    {
+    if ( !iCredentials )
+        {
+        return KNullDesC8();
+        }
+    
+    return iCredentials->Username();
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::UsenameForIndication
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CSTUNClientImplementation::PasswordForIndication()
+    {
+    if ( !iCredentials )
+        {
+        return KNullDesC8();
+        }
+    
+    return iCredentials->Password();
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::InformWaitingBindingsL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::InformWaitingBindingsL() const
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::InformWaitingBindingsL" )
+    __TEST_INVARIANT;
+
+    for ( TInt i = 0; i < iBindings.Count(); ++i )
+        {
+        if ( iBindings[i]->Implementation().IsWaitingSharedSecret() )
+            {
+            PassSharedSecretToBindingL( *iBindings[i] );
+            }
+        }
+    __STUNTURNCLIENT( "CSTUNClientImplementation::InformWaitingBindingsL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::HandleSharedSecretErrorL
+// ---------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::HandleSharedSecretErrorL( TInt aError )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::HandleSharedSecretErrorL" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L( aError != KErrNone, KErrArgument );
+
+     if ( aError == KErrCouldNotConnect || aError == KErrTimedOut )
+         {
+         if ( iTcpAddresses.Count() > 1 )
+             {
+             // Remove the failed address. Remain in the current state.
+             iTcpAddresses.Remove( 0 );
+             GetSharedSecretFromServerL();
+             }
+         else
+             {
+             iObtainSharedSecret = EFalse;
+             if ( !IsInitialized() )
+                {
+                PassInitCompletedL( KErrNone );
+                }
+             ChangeState( iReady );
+             }
+         }
+     else
+         {
+         Terminate( aError );
+         }
+ 
+     __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::HandleSharedSecretErrorL end" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNClientImplementation::DoesSharedSecretMatch
+// Username and password can be empty.
+// ---------------------------------------------------------------------------
+//
+TBool CSTUNClientImplementation::DoesSharedSecretMatch(
+    const TDesC8& aUsername,
+    const TDesC8& aPassword ) const
+    {
+    __TEST_INVARIANT;
+
+    return ( iCredentials &&
+             iCredentials->Compare( aUsername, aPassword ) ) ||
+           ( iSharedSecret &&
+             aUsername.Compare( iSharedSecret->Username() ) == 0 &&
+             aPassword.Compare( iSharedSecret->Password() ) == 0 );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNClientImplementation::RemoveAddress
+// -----------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::RemoveAddress( const TInetAddr& aAddress )
+    {
+    __STUNTURNCLIENT( "CSTUNClientImplementation::RemoveAddress" )
+    __TEST_INVARIANT;
+
+    for ( TInt i = 0; i < iUdpAddresses.Count(); ++i )
+        {
+        if ( iUdpAddresses[ i ].CmpAddr( aAddress ) )
+            {
+            iUdpAddresses.Remove( i );
+            }
+        }
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT( "CSTUNClientImplementation::RemoveAddress end" )
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNClientImplementation::__DbgTestInvariant
+// -----------------------------------------------------------------------------
+//
+void CSTUNClientImplementation::__DbgTestInvariant() const
+    {
+#if defined( _DEBUG )
+    if ( ( iState == iResolvingTCP || iState == iResolvingUDP ) &&
+         ( !iResolver || !iServerAddress ) )
+        {
+        User::Invariant();
+        }
+    if ( !iTransactionIDGenerator ||
+         !iAsyncCallback ||
+         !iResolvingTCP ||
+         !iResolvingUDP ||
+         !iGetSharedSecret ||
+         !iReady )
+        {
+        User::Invariant();
+        }
+#endif
+    }