natfw/natfwstunturnclient/src/cstunsharedsecret.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwstunturnclient/src/cstunsharedsecret.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,621 @@
+/*
+* Copyright (c) 2006 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 "stunassert.h"
+#include "natfwunsaflog.h"
+#include "cnatfwunsaftlstransport.h"
+#include "natfwunsafsharedsecretrequest.h"
+#include "natfwunsaftextattribute.h"
+#include "natfwunsaferrorcodeattribute.h"
+#include "natfwunsafusernameattribute.h"
+#include "natfwunsafrealmattribute.h"
+#include "natfwunsafnonceattribute.h"
+#include "cstunsharedsecret.h"
+#include "cstunsharedsecretconnecting.h"
+#include "cstunsharedsecretwaitresponse.h"
+#include "cstunsharedsecretactive.h"
+#include "cstunsharedsecretwaittoretry.h"
+#include "msharedsecretobserver.h"
+#include "ctransactionidgenerator.h"
+#include "stunutils.h"
+#include "stunturnclientlogs.h"
+#include "natfwstunclientdefs.h"
+
+
+const TInt KMaxSameErrorCount = 3;
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::NewL
+// ---------------------------------------------------------------------------
+//
+CSTUNSharedSecret*
+CSTUNSharedSecret::NewL( RSocketServ& aSocketServer,
+                         RConnection& aConnection,
+                         CDeltaTimer& aTimer,
+                         const TInetAddr& aAddr,
+                         CTransactionIDGenerator& aTransactionIDGenerator,
+                         MSharedSecretObserver& aObserver,
+                         const TDesC8& aLtUsername,
+                         const TDesC8& aLtPassword )
+    {
+    CSTUNSharedSecret* self =
+        new ( ELeave ) CSTUNSharedSecret( aTimer,
+                                          aTransactionIDGenerator,
+                                          aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL( aSocketServer, aConnection, aAddr, 
+        aLtUsername, aLtPassword );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::CSTUNSharedSecret
+// ---------------------------------------------------------------------------
+//
+CSTUNSharedSecret::CSTUNSharedSecret(
+    CDeltaTimer& aTimer,
+    CTransactionIDGenerator& aTransactionIDGenerator,
+    MSharedSecretObserver& aObserver ) :
+    CSTUNTimerUser( aTimer ),
+    iObserver( aObserver ),
+    iTransactionIDGenerator( aTransactionIDGenerator )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::CSTUNSharedSecret
+// Dummy implementation. Default constructor is declared private and not used.
+// ---------------------------------------------------------------------------
+//
+CSTUNSharedSecret::CSTUNSharedSecret() :
+    CSTUNTimerUser( *( CDeltaTimer* )0x1 ),
+    iObserver( *( MSharedSecretObserver* )0x1 ),
+    iTransactionIDGenerator( *( CTransactionIDGenerator* )0x1  )
+    {        
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::CSTUNSharedSecret
+// Dummy implementation. Copy constructor is declared private and not used.
+// ---------------------------------------------------------------------------
+//
+CSTUNSharedSecret::CSTUNSharedSecret(
+    const CSTUNSharedSecret& aSharedSecret ) :
+    CSTUNTimerUser( *( CDeltaTimer* )0x1 ),
+    iObserver( aSharedSecret.iObserver ),
+    iTransactionIDGenerator( aSharedSecret.iTransactionIDGenerator )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::ConstructL( RSocketServ& aSocketServer,
+                                    RConnection& aConnection,
+                                    const TInetAddr& aAddr,
+                                    const TDesC8& aLtUsername,
+                                    const TDesC8& aLtPassword )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::ConstructL" )
+    
+    iActive = new ( ELeave ) CSTUNSharedSecretActive;
+    iWaitToRetry = new ( ELeave ) CSTUNSharedSecretWaitToRetry;
+    iWaitResponse =
+        new ( ELeave ) CSTUNSharedSecretWaitResponse( *iActive, *iWaitToRetry );
+    iConnecting = new ( ELeave ) CSTUNSharedSecretConnecting( *iWaitResponse );    
+    iWaitToRetry->SetNeighbourStates( *iWaitResponse );
+    iState = iConnecting;
+    
+    if ( aLtUsername.Length() > 0 && aLtPassword.Length() > 0 )
+        {
+        iLtUsername = aLtUsername.AllocL();
+        iLtPassword = aLtPassword.AllocL();
+        }
+
+    iTlsTransport = CNATFWUNSAFTlsTransport::NewL( aSocketServer,
+                                                   aConnection,
+                                                   aAddr,
+                                                   *this );
+    
+    StartTimer( KTlsHandshakeTimeout );
+    }
+       
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::~CSTUNSharedSecret
+// ---------------------------------------------------------------------------
+//
+CSTUNSharedSecret::~CSTUNSharedSecret()
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::~CSTUNSharedSecret" )
+    delete iLtUsername;
+    delete iLtPassword;
+    delete iNonce;
+    delete iRealm;  
+    delete iTlsTransport;
+    delete iRequest;
+    delete iUsername;
+    delete iPassword;
+    
+    delete iConnecting;
+    delete iWaitResponse;
+    delete iWaitToRetry;
+    delete iActive;
+    iErrorBuffer.Close();
+    }
+    
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::TlsConnectedL
+// ---------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::TlsConnectedL()
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::TlsConnectedL" )
+    __TEST_INVARIANT;
+
+    if ( iState )
+        {
+        // Stop TLS handshake timer
+        StopTimer();
+        iState->TlsConnectedL( *this );
+        }
+
+    __TEST_INVARIANT;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::IncomingMessageL
+// ---------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::IncomingMessageL( CNATFWUNSAFMessage* aMessage )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::IncomingMessageL" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L( aMessage != NULL, KErrArgument );
+
+    if ( iState )
+        {
+        iState->IncomingMessageL( *this, aMessage );
+        }
+        
+    __TEST_INVARIANT;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::ErrorOccured
+// ---------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::ErrorOccured( TInt aError )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::ErrorOccured" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument );
+
+    if ( iState )
+        {
+        iState->ErrorOccured( *this, aError );
+        }
+        
+    // Do not call __TEST_INVARIANT here because the previous call might have
+    // led to deletion of this object.
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::TimerExpiredL
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::TimerExpiredL()
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::TimerExpiredL" )
+    if ( iState )
+        {
+        iState->TimerExpiredL( *this );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::LeaveFromTimerExpired
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::LeaveFromTimerExpired( TInt aError )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::LeaveFromTimerExpired" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument );
+
+    Terminate( aError );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::Username
+// -----------------------------------------------------------------------------
+//
+const TDesC8& CSTUNSharedSecret::Username() const
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::Username" )
+    __TEST_INVARIANT;
+
+    if ( iUsername )
+        {
+        return *iUsername;
+        }
+
+    return KNullDesC8;    
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::Password
+// -----------------------------------------------------------------------------
+//
+const TDesC8& CSTUNSharedSecret::Password() const
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::Password" )
+    __TEST_INVARIANT;
+
+    if ( iPassword )
+        {
+        return *iPassword;
+        }
+
+    return KNullDesC8;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::ChangeState
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::ChangeState( const CSTUNSharedSecretState* aNewState )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::ChangeState" )
+    __TEST_INVARIANT;
+
+    iState = aNewState;
+
+    __TEST_INVARIANT;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::Terminate
+// ---------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::Terminate( TInt aError )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::Terminate" )
+    __TEST_INVARIANT;
+    // Terminate only once
+    __STUN_ASSERT_RETURN( iState != NULL, KErrDied );
+    __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument );
+    NATFWUNSAF_INTLOG( "STUNSharedSecret terminated, reason", aError )
+
+    ChangeState( NULL );
+    TRAP_IGNORE( iObserver.SharedSecretErrorL( aError ) )
+    
+    // Do not call __TEST_INVARIANT here because the call to observer's
+    // SharedSecretErrorL might have led to deletion of this object.
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::SendRequestL
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::SendRequestL()
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::SendRequestL in" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L( !iRequest, KErrAlreadyExists );
+
+    TNATFWUNSAFTransactionID transactionID;
+    iTransactionIDGenerator.GetIDL( this, sizeof( *this ), transactionID );
+    iRequest = CNATFWUNSAFSharedSecretRequest::NewL( transactionID );
+  
+    
+    if ( iLtUsername && iLtPassword && iAddUsernameAttr )
+        {
+        __STUNTURNCLIENT( "CSTUNSharedSecret::SendRequestL -username attr" )
+        iRequest->AddAttributeL(
+            CNATFWUNSAFUsernameAttribute::NewLC( *iLtUsername ) );
+        CleanupStack::Pop(); //CNATFWUNSAFUsernameAttribute
+        }
+    
+    if ( iRealm )
+        {
+        __STUNTURNCLIENT( "CSTUNSharedSecret::SendRequestL -realm attr" )
+        iRequest->AddAttributeL( CNATFWUNSAFRealmAttribute::NewLC( *iRealm ) );
+        CleanupStack::Pop(); //CNATFWUNSAFRealmAttribute        
+        }
+    
+    if ( iNonce )
+        {
+        __STUNTURNCLIENT( "CSTUNSharedSecret::SendRequestL -nonce attr" )
+        iRequest->AddAttributeL( CNATFWUNSAFNonceAttribute::NewLC( *iNonce ) );
+        CleanupStack::Pop(); //CNATFWUNSAFNonceAttribute        
+        }
+    
+    if ( iLtUsername && iLtPassword && iRealm )
+        {
+        // create credential string; username:realm:password
+        // space for two colons (:)
+        __STUNTURNCLIENT( "CSTUNSharedSecret::\
+            SendRequestL make credential string" )
+        const TInt marks(2);
+        _LIT8( Kcolon, ":" ); 
+        TInt stringlength( iLtUsername->Length() + 
+            iLtPassword->Length() + iRealm->Length() + marks );
+        
+        HBufC8* credential = HBufC8::NewL( stringlength );
+        TPtr8 des = credential->Des();
+        des.Append( *iLtUsername );
+        des.Append( Kcolon );
+        des.Append( *iRealm );
+        des.Append( Kcolon );
+        des.Append( *iLtPassword );
+        
+        CleanupStack::PushL( credential );
+        __STUNTURNCLIENT_STR8( "CSTUNSharedSecret::\
+            SendRequestL credential string: ", *credential )
+        iTlsTransport->SendL( *iRequest, *credential );
+        CleanupStack::PopAndDestroy( credential );
+        }
+    else
+        {
+        // A null descriptor used for long term shared secret for now.
+        iTlsTransport->SendL( *iRequest, KNullDesC8 );
+        }
+    
+    StartTimer( KSharedSecretRequestTimeout );
+    __STUNTURNCLIENT( "CSTUNSharedSecret::SendRequestL End" )
+    __TEST_INVARIANT;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNSharedSecret::CheckMessage
+// ---------------------------------------------------------------------------
+//
+TBool CSTUNSharedSecret::CheckMessage( 
+    const CNATFWUNSAFMessage& aMessage ) const
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::CheckMessage in" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_RETURN_VALUE( iRequest != NULL, EFalse );
+
+    __STUNTURNCLIENT_STR8( "CSTUNSharedSecret::\
+    CheckMessage transcation id from message :", aMessage.TransactionID() )
+    __STUNTURNCLIENT_STR8( "CSTUNSharedSecret::\
+    CheckMessage transcation id from request :", iRequest->TransactionID() )
+    
+    if ( aMessage.Type() == CNATFWUNSAFMessage::ESharedSecretResponse &&
+         aMessage.Validate() )
+        {
+        __STUNTURNCLIENT( "CSTUNSharedSecret::CheckMessage\
+        SharedSecretResponse -> CORRECT THIS IMPLEMENTATION AFTER SERVER\
+        DOES NOT MESS UP THE TRANSACTION ID - TODO" )
+        return ETrue;
+        }
+    
+    else if ( aMessage.Validate() &&
+        ( aMessage.TransactionID() == iRequest->TransactionID() ) &&
+        ( aMessage.Type() == CNATFWUNSAFMessage::ESharedSecretErrorResponse ) )
+        {
+        return ETrue;
+        }
+    else 
+        {
+        return EFalse;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::ResponseReceivedL
+// Store username and password before calling SharedSecretObtainedL.
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::ResponseReceivedL( const CNATFWUNSAFMessage& aResponse )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::ResponseReceivedL" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L( !iUsername && !iPassword, KErrAlreadyExists );
+    __STUN_ASSERT_L( aResponse.Type() == CNATFWUNSAFMessage::ESharedSecretResponse,
+                     KErrArgument );
+    NATFWUNSAF_LOG( "STUNSharedSecret received SharedSecretResp" )
+
+    StopTimer();
+    StoreValueL( aResponse.Attribute( CNATFWUNSAFAttribute::EUsername ), &iUsername );
+    StoreValueL( aResponse.Attribute( CNATFWUNSAFAttribute::EPassword ), &iPassword );
+    
+    __STUNTURNCLIENT_STR8( "CSTUNSharedSecret::username:", *iUsername )
+    __STUNTURNCLIENT_STR8( "CSTUNSharedSecret::password:", *iPassword )
+    
+    NATFWUNSAF_BYTESTREAMLOG( "username", *iUsername )
+    NATFWUNSAF_BYTESTREAMLOG( "password", *iPassword )
+    
+    iErrorBuffer.Reset();
+
+    // Close TLS connection
+    delete iTlsTransport;
+    iTlsTransport = NULL;
+
+    iObserver.SharedSecretObtainedL();
+
+    __TEST_INVARIANT;
+    }    
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::StoreValueL
+// Empty value is an error. Don't use __TEST_INVARIANT, as it checks username
+// and password.
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::StoreValueL( CNATFWUNSAFAttribute* aAttribute,
+                                     HBufC8** aDest ) const
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::StoreValueL" )
+    __STUN_ASSERT_L( aAttribute, KErrCorrupt );
+
+    const TDesC8& value =
+        static_cast<CNATFWUNSAFTextAttribute*>( aAttribute )->Value();
+    __ASSERT_ALWAYS( value.Length() > 0 && aDest != NULL,
+        User::Leave( KErrArgument ) );
+    *aDest = value.AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::ErrorResponseReceivedL
+// If 5xx is received, wait a few seconds, then retry.
+// -----------------------------------------------------------------------------
+//
+TBool CSTUNSharedSecret::ErrorResponseReceivedL( 
+    const CNATFWUNSAFMessage& aResponse )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::ErrorResponseReceivedL in" )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L(
+        aResponse.Type() == CNATFWUNSAFMessage::ESharedSecretErrorResponse,
+        KErrArgument );
+
+    StopTimer();
+
+    CNATFWUNSAFErrorCodeAttribute* errorCode =
+        static_cast<CNATFWUNSAFErrorCodeAttribute*>(
+            aResponse.Attribute( CNATFWUNSAFAttribute::EErrorCode ) );
+    __STUN_ASSERT_L( errorCode, KErrCorrupt );
+    
+    TInt error( errorCode->ResponseCode() );
+    
+    __STUNTURNCLIENT_INT1( "CSTUNSharedSecret::ErrorResponseReceivedL:",
+        error )
+    
+    iErrorBuffer.AppendL( error );
+    TInt count( iErrorBuffer.Count() );
+    TInt sameErrorCount(0);
+    for ( TInt i(0); i < count; i++ )
+        {
+        if ( iErrorBuffer[i] == error )
+            {
+            sameErrorCount++;
+            
+            // if same error occurs "KMaxSameErrorCount" times,
+            // it is time to quit retrying
+            if ( KMaxSameErrorCount <= sameErrorCount )
+                {
+                return EFalse;
+                }
+            }
+        }
+    
+    if ( STUNUtils::Is5xxResponse( error ) )
+        {
+        delete iRequest;
+        iRequest = NULL;
+        StartTimer( STUNUtils::EWaitBeforeRetryDuration );        
+        return ETrue;
+        }
+    
+    if( IsExpectedError( error ) )
+        {
+        SaveRealmAndNonceL( aResponse );
+                
+        iTlsTransport->ContinueListeningL();
+        delete iRequest;
+        iRequest = NULL;
+        StartTimer( STUNUtils::ERetryImmediately );
+        return ETrue;
+        }
+    
+    return EFalse;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::IsExpectedError
+// -----------------------------------------------------------------------------
+//
+TBool CSTUNSharedSecret::IsExpectedError( TInt aError )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::IsExpectedError" )
+    
+    if ( E401Unauthorized == aError )
+        {
+        iAddUsernameAttr = ETrue;
+        }
+    
+    return ( E401Unauthorized == aError || E435MissingNonce == aError || 
+             E438StaleNonce == aError );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::SaveRealmAndNonceL
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::SaveRealmAndNonceL( 
+    const CNATFWUNSAFMessage& aResponse )
+    {
+    __STUNTURNCLIENT( "CSTUNSharedSecret::SaveRealmAndNonceL in" )
+    
+    CNATFWUNSAFAttribute* tmp = aResponse.Attribute(
+        CNATFWUNSAFAttribute::ENonce );
+    
+    if ( tmp )
+        {
+        __STUNTURNCLIENT( "CSTUNSharedSecret::SaveRealmAndNonceL nonce found" )
+        CNATFWUNSAFNonceAttribute* nonceAttrib =
+            static_cast<CNATFWUNSAFNonceAttribute*>( tmp );
+        
+        delete iNonce;
+        iNonce = NULL;
+        iNonce = nonceAttrib->Value().AllocL();
+        }
+    
+    
+    CNATFWUNSAFAttribute* temp = aResponse.Attribute(
+        CNATFWUNSAFAttribute::ERealm );
+    
+    if ( temp )
+        {
+        __STUNTURNCLIENT( "CSTUNSharedSecret::SaveRealmAndNonceL realm found" )
+        CNATFWUNSAFRealmAttribute* realmAttrib =
+            static_cast<CNATFWUNSAFRealmAttribute*>( temp );
+        
+        delete iRealm;
+        iRealm = NULL;
+        iRealm = realmAttrib->Value().AllocL();
+        }
+
+    __STUNTURNCLIENT( "CSTUNSharedSecret::SaveRealmAndNonceL out" )
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNSharedSecret::__DbgTestInvariant
+// Both username and password (or neither) must exist.
+// -----------------------------------------------------------------------------
+//
+void CSTUNSharedSecret::__DbgTestInvariant() const
+    {
+#if defined( _DEBUG )
+    if ( !iConnecting || !iWaitResponse || !iWaitToRetry || !iActive ||
+         ( iUsername && !iPassword ) || ( !iUsername && iPassword ) )
+        {
+        __STUNTURNCLIENT( "CSTUNSharedSecret::__DbgTestInvariant -> PANIC" )
+        User::Invariant();
+        }
+#endif
+    }