diff -r 000000000000 -r 1bce908db942 natfw/natfwstunturnclient/src/cstunsharedsecret.cpp --- /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( 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( + 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( 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( 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 + }