diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/sipsecdigestcache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/sipsecdigestcache.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,888 @@ +// Copyright (c) 2008-2009 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: +// Name : sipsecdigestcache.cpp +// Part of : SIPSec +// Version : SIP/6.0 +// + + + +#include "SipLogs.h" +#include "siperr.h" +#include "SipAssert.h" +#include "sipsecdigestcache.h" +#include "CSIPSecDigestCacheEntry.h" +#include "CSIPSecDigestObserver.h" +#include "CSIPSecUserRecord.h" +#include "CSIPSecSIMRecord.h" +#include "CSIPSecCredentials.h" +#include "CSIPSecChallengeAKA.h" +#include "RSIPSecChallengeResolver.h" +#include "MSIPSecUser.h" +#include "sipstrings.h" +#include "sipstrconsts.h" +#include "siprequest.h" +#include "sipresponse.h" +#include "sipsecdigestcontext.h" +#include "sipauthenticateheaderbase.h" + + +const TInt TSIPSecDigestCacheEntryIterator::iSIPSecOffset = + _FOFF( TSIPSecDigestCacheEntryIterator, iLink ); + +// ============================ MEMBER FUNCTIONS =============================== + + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::NewL +// ---------------------------------------------------------------------------- +// +CSIPSecDigestCache* CSIPSecDigestCache::NewL( MTimerManager& aTimerManager ) + { + CSIPSecDigestCache* self = NewLC( aTimerManager ); + CleanupStack::Pop( self ); + return self; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::NewLC +// ---------------------------------------------------------------------------- +// +CSIPSecDigestCache* CSIPSecDigestCache::NewLC( MTimerManager& aTimerManager ) + { + CSIPSecDigestCache* self = + new ( ELeave ) CSIPSecDigestCache( aTimerManager ); + CleanupStack::PushL( self ); + return self; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache +// ---------------------------------------------------------------------------- +// +CSIPSecDigestCache::CSIPSecDigestCache( MTimerManager& aTimerManager ) : + iProxyList( CSIPSecDigestCacheEntry::iSIPSecOffset ), + iProxyListIter( iProxyList ), + iEndpointList( CSIPSecDigestCacheEntry::iSIPSecOffset ), + iEndpointListIter( iEndpointList ), + iCredentialsList( CSIPSecUserRecord::iSIPSecOffset ), + iCredentialsListIter( iCredentialsList ), +#ifdef CPPUNIT_TEST + // Use granularity 1 to make each append operation to allocate memory. + iDigestObservers( 1 ), +#endif + iTimerManager( aTimerManager ) + { + } + +// ---------------------------------------------------------------------------- +// ~CSIPSecDigestCache +// ---------------------------------------------------------------------------- +// +CSIPSecDigestCache::~CSIPSecDigestCache() + { + RemoveAllEntries(); + RemoveAllCredentials(); + iDigestObservers.ResetAndDestroy(); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::InitializeIterator +// ---------------------------------------------------------------------------- +// +void +CSIPSecDigestCache::InitializeIterator( TSIPSecDigestCacheIterator& aIterator ) + { + iProxyListIter.SetToFirst(); + iEndpointListIter.SetToFirst(); + + aIterator.iList.Reset(); + aIterator.iList.AddLast( iProxyListIter ); + aIterator.iList.AddLast( iEndpointListIter ); + aIterator.iListIterator.SetToFirst(); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::AddEntry +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::AddEntry( CSIPSecDigestCacheEntry* aCacheEntry ) + { + __SIP_ASSERT_RETURN( aCacheEntry, KErrArgument ); + __SIP_ASSERT_RETURN( !IsEntryInCache( *aCacheEntry ), KErrAlreadyExists ); + + SelectCache( *aCacheEntry ).AddLast( *aCacheEntry ); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RemoveEntry +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::RemoveEntry( CSIPSecDigestCacheEntry& aCacheEntry ) + { + __SIP_ASSERT_RETURN( IsEntryInCache( aCacheEntry ), KErrNotFound ); + + aCacheEntry.UserData().CredentialsDetach(); + SelectCache( aCacheEntry ).Remove( aCacheEntry ); + delete &aCacheEntry; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RemoveCacheEntry +// ---------------------------------------------------------------------------- +// +TBool CSIPSecDigestCache::RemoveCacheEntry( CSIPSecDigestCacheEntry& aEntry, + const MSIPSecUser& aUser ) + { + CSIPSecUserRecord& record = aEntry.UserData(); + RemoveEntry( aEntry ); + if ( record.CredentialsAttached() ) + { + ChangeRecordUserIfNeeded( record, aUser ); + return EFalse; + } + + __SIP_LOG( "SIPSecDigestCache:RemoveCacheEntry record not used" ) + __SIP_ASSERT_RETURN_VALUE( IsCredentialsInList( record ), KErrNotFound ); + iCredentialsList.Remove( record ); + delete &record; + return ETrue; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::IsEntryInCache +// ---------------------------------------------------------------------------- +// +TBool CSIPSecDigestCache::IsEntryInCache( CSIPSecDigestCacheEntry& aCacheEntry ) + { + TSIPSecDigestCacheEntryIterator entryIterator = + TSIPSecDigestCacheEntryIterator( SelectCache( aCacheEntry ) ); + + CSIPSecDigestCacheEntry* entry( NULL ); + TBool found( EFalse ); + while ( !found && ( entry = entryIterator.Next() ) != NULL ) + { + found = ( entry == &aCacheEntry ); + } + return found; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::SelectCache +// ---------------------------------------------------------------------------- +// +TSglQue< CSIPSecDigestCacheEntry >& +CSIPSecDigestCache::SelectCache( const CSIPSecDigestCacheEntry& aCacheEntry ) + { + if ( aCacheEntry.Type() == CSIPSecDigest::EEndPoint ) + { + return iEndpointList; + } + return iProxyList; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::AddUserCredentials +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::AddUserCredentials( CSIPSecUserRecord* aCredentials ) + { + __SIP_ASSERT_RETURN( aCredentials, KErrArgument ); + __SIP_ASSERT_RETURN( !IsCredentialsInList( *aCredentials ), + KErrAlreadyExists ); + iCredentialsList.AddLast( *aCredentials ); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::SearchRecordForResponse +// Cache can have only one entry with matching MSIPSecUser and realm. +// ---------------------------------------------------------------------------- +// +CSIPSecUserRecord* +CSIPSecDigestCache::SearchRecordForResponse( const TDesC8& aRealm, + const MSIPSecUser& aUser, + TRegistrationId aRegistrationId ) + { + __ASSERT_ALWAYS( aRealm.Length() > 0, + User::Panic( _L( "DigestCache:SearchRecForResp" ), KErrArgument ) ); + + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( record->IsSameRealm( aRealm ) && + record->CompareUser( aUser, aRegistrationId ) ) + { + return record; + } + } + + return NULL; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::SearchRecord +// ---------------------------------------------------------------------------- +// +CSIPSecUserRecord* +CSIPSecDigestCache::SearchRecord( const TDesC8& aRealm, + TTransactionId aTransactionId ) + { + __ASSERT_ALWAYS( aRealm.Length() > 0, + User::Panic( _L( "DigestCache:SearchRec(id)" ), KErrArgument ) ); + + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( record->IsSameRealm( aRealm ) && + record->TransactionIdPassedToClient() == aTransactionId ) + { + return record; + } + } + + return NULL; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::SearchRecord +// ---------------------------------------------------------------------------- +// +CSIPSecUserRecord* CSIPSecDigestCache::SearchRecord( const TDesC8& aRealm, + const MSIPSecUser& aUser ) + { + __ASSERT_ALWAYS( aRealm.Length() > 0, + User::Panic( _L( "DigestCache:SearchRec(user)" ), KErrArgument ) ); + + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( record->IsSameRealm( aRealm ) && &aUser == &record->SIPSecUser() ) + { + return record; + } + } + + return NULL; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RemoveAllEntries +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::RemoveAllEntries() + { + RemoveAllEntriesFromList( iProxyList ); + RemoveAllEntriesFromList( iEndpointList ); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RemoveAllEntriesFromList +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::RemoveAllEntriesFromList( + TSglQue& aList ) + { + if ( !aList.IsEmpty() ) + { + CSIPSecDigestCacheEntry* entry( NULL ); + TSIPSecDigestCacheEntryIterator entryIterator = + TSIPSecDigestCacheEntryIterator( aList ); + + while ( ( entry = entryIterator.Next() ) != NULL ) + { + aList.Remove( *entry ); + delete entry; + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RemoveAllCredentials +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::RemoveAllCredentials() + { + if ( !iCredentialsList.IsEmpty() ) + { + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + iCredentialsList.Remove( *record ); + delete record; + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::IsCredentialsInList +// ---------------------------------------------------------------------------- +// +TBool CSIPSecDigestCache::IsCredentialsInList( + const CSIPSecUserRecord& aCredentials ) + { + if ( !iCredentialsList.IsEmpty() ) + { + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( record == &aCredentials ) + { + return ETrue; + } + } + } + return EFalse; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::ClearCache +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::ClearCache( const MSIPSecUser& aUser ) + { + RemoveUsedEntry( iProxyList, aUser ); + RemoveUsedEntry( iEndpointList, aUser ); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RemoveUsedEntry +// ---------------------------------------------------------------------------- +// +void +CSIPSecDigestCache::RemoveUsedEntry( TSglQue< CSIPSecDigestCacheEntry >& aList, + const MSIPSecUser& aUser ) + { + if ( !aList.IsEmpty() ) + { + CSIPSecDigestCacheEntry* entry( NULL ); + TSIPSecDigestCacheEntryIterator entryIter = + TSIPSecDigestCacheEntryIterator( aList ); + + while ( ( entry = entryIter.Next() ) != NULL ) + { + // When removing cache items, do NOT compare trusted user + if ( &entry->SIPSecUser() == &aUser ) + { + RemoveCacheEntry( *entry, aUser ); + } + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::ClearCache +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::ClearCache( CSIPSecUserRecord& aCredentials, + TBool aAKAOnly ) + { + RemoveMatchingEntry( iProxyList, aCredentials, aAKAOnly ); + RemoveMatchingEntry( iEndpointList, aCredentials, aAKAOnly ); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RemoveMatchingEntry +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::RemoveMatchingEntry( + TSglQue< CSIPSecDigestCacheEntry >& aList, + CSIPSecUserRecord& aCredentials, + TBool aAKAOnly ) + { + if ( !aList.IsEmpty() ) + { + CSIPSecDigestCacheEntry* entry( NULL ); + TSIPSecDigestCacheEntryIterator entryIter = + TSIPSecDigestCacheEntryIterator( aList ); + + while ( ( entry = entryIter.Next() ) != NULL ) + { + if ( entry->HoldsUserData( aCredentials ) && + ( !aAKAOnly || + ( static_cast< CSIPSecCredentials* >( entry )->Challenge(). + Algorithm().AlgorithmName() == + CSIPSecChallengeAKA::SupportedAlgorithm() ) ) ) + { + if ( RemoveCacheEntry( *entry, entry->SIPSecUser() ) ) + { + // Removed aCredentials, nothing refers to it, so exit loop + return; + } + } + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::ClearAKAEntriesWithOldRealm +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::ClearAKAEntriesWithOldRealm( const TDesC8& aRealm ) + { + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( !record->IsSameRealm( aRealm ) ) + { + ClearCache( *record, ETrue ); + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::RegisterObserverL +// Check if aObserver has a matching CSIPSecDigestObserver. If not, create +// CSIPSecDigestObserver for it. Each SIP response has its own aObserver. +// ---------------------------------------------------------------------------- +// +CSIPSecDigestObserver* CSIPSecDigestCache::RegisterObserverL( + MSIPSecSecurityMechanismObserver& aObserver, + CSIPSecUserRecord& aUserData ) + { + CSIPSecDigestObserver* observer( NULL ); + TInt i( 0 ); + while ( !observer && i < iDigestObservers.Count() ) + { + observer = iDigestObservers[ i++ ]; + observer = observer->HasObserver( aObserver ) ? observer : NULL; + } + + if ( !observer ) + { + observer = aUserData.CreateObserverL( aObserver ); + CleanupStack::PushL( observer ); + iDigestObservers.AppendL( observer ); + CleanupStack::Pop( observer ); + } + + return observer; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::CancelPendingOperations +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::CancelPendingOperations( + MSIPSecSecurityMechanismObserver* aObserver ) + { + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + record->CancelPendingOperations( aObserver ); + } + + CleanObservers(); + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::Cancel +// ---------------------------------------------------------------------------- +// +TInt CSIPSecDigestCache::Cancel( TTransactionId aTransactionId, + const TDesC8& aRealm, + const MSIPSecUser* aTrustedUser ) + { + if ( aRealm.Length() == 0 ) + { + return KErrArgument; + } + + TInt status( KErrNotFound ); + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( record->IsSameRealm( aRealm ) && + ( record->TransactionIdPassedToClient() == aTransactionId || + &record->SIPSecUser() == aTrustedUser ) ) + { + status = KErrNone; // At least one found + record->CancelPendingOperations( NULL /* cancel all */ ); + } + } + + CleanObservers(); + return status; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::Remove +// ---------------------------------------------------------------------------- +// +TInt CSIPSecDigestCache::Remove( const TDesC8& aRealm ) + { + if ( aRealm.Length() == 0 ) + { + return KErrArgument; + } + + TInt status( KErrNotFound ); + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( record->IsSameRealm( aRealm ) ) + { + status = KErrNone; // At least one found + // Remove entries pointing to record, then remove record. + ClearCache( *record, EFalse ); + } + } + + CleanObservers(); + return status; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::CountResponses +// There can be just one record per realm/transaction id pair, as many SIPSec +// users can't have the same transaction id. Cache has just one IMS record. +// Compare the real transaction ids, regardless of the value returned by +// MSIPSecUser::PassOnlyRealmsToUser(). +// ---------------------------------------------------------------------------- +// +TInt CSIPSecDigestCache::CountResponses( CSIPResponse& aResponse, + CSIPRequest& aRequest, + TTransactionId aTransactionId, + RStringF aDefaultAlgorithm ) + { + TInt status( KErrNone ); + + RStringF alg; + RStringF dummyQop; + RSIPSecChallengeResolver::GetDigestParamsFromSecurityServer( aResponse, + alg, + dummyQop ); + CSIPSecUserRecord* record( NULL ); + iCredentialsListIter.SetToFirst(); + while ( ( record = iCredentialsListIter++ ) != NULL ) + { + if ( record->Type() == CSIPSecUserRecord::EIMS && + record->TransactionId() == aTransactionId ) + { + TBool match( EFalse ); + if ( !HandleChallenges( aResponse, + alg, + aDefaultAlgorithm, + record->Realm(), + match ) ) + { + __SIP_ASSERT_RETURN_VALUE( !match, KErrAlreadyExists ); + match = HandleAuthorizations( aRequest, + alg, + aDefaultAlgorithm, + record->Realm() ); + } + if ( match && + static_cast< CSIPSecSIMRecord* >( record )-> + UpdateMessageCounter( aResponse.ResponseCode() ) ) + { + status = KErrSIPForbidden; + } + } + } + return status; + } + +// ---------------------------------------------------------------------------- +// CSIPSecDigestCache::CleanObservers +// ---------------------------------------------------------------------------- +// +void CSIPSecDigestCache::CleanObservers() + { + TInt i( 0 ); + while ( i < iDigestObservers.Count() ) + { + CSIPSecDigestObserver* observer = iDigestObservers[ i ]; + if ( observer->IsCompleted() ) + { + iDigestObservers.Remove( i ); + delete observer; + } + else + { + ++i; + } + } + } + +// ----------------------------------------------------------------------------- +// CSIPSecDigestCache::HandleChallenges +// ----------------------------------------------------------------------------- +// +TBool CSIPSecDigestCache::HandleChallenges( CSIPResponse& aResponse, + RStringF aAlgorithm, + RStringF aDefaultAlgorithm, + const TDesC8& aRealm, + TBool& aMatch ) const + { + TBool proxyChallenges( EFalse ); + TBool endpointChallenges( EFalse ); + + aMatch = HandleAuthHeaders( aResponse, + aAlgorithm, + aDefaultAlgorithm, + SIPStrings::StringF( SipStrConsts::EProxyAuthenticateHeader ), + aRealm, + ETrue, + proxyChallenges ) || + HandleAuthHeaders( aResponse, + aAlgorithm, + aDefaultAlgorithm, + SIPStrings::StringF( SipStrConsts::EWWWAuthenticateHeader ), + aRealm, + ETrue, + endpointChallenges ); + return proxyChallenges || endpointChallenges; + } + +// ----------------------------------------------------------------------------- +// CSIPSecDigestCache::HandleAuthorizations +// ----------------------------------------------------------------------------- +// +TBool CSIPSecDigestCache::HandleAuthorizations( CSIPRequest& aRequest, + RStringF aAlgorithm, + RStringF aDefaultAlgorithm, + const TDesC8& aRealm ) const + { + TBool dummy( EFalse ); + return HandleAuthHeaders( aRequest, + aAlgorithm, + aDefaultAlgorithm, + SIPStrings::StringF( SipStrConsts::EAuthorizationHeader ), + aRealm, + EFalse, + dummy ) || + HandleAuthHeaders( aRequest, + aAlgorithm, + aDefaultAlgorithm, + SIPStrings::StringF( SipStrConsts::EProxyAuthorizationHeader ), + aRealm, + EFalse, + dummy ); + } + +// ----------------------------------------------------------------------------- +// CSIPSecDigestCache::HandleAuthHeaders +// ----------------------------------------------------------------------------- +// +TBool CSIPSecDigestCache::HandleAuthHeaders( CSIPMessage& aMessage, + RStringF aAlgorithm, + RStringF aDefaultAlgorithm, + RStringF aHeaderName, + const TDesC8& aRealm, + TBool aCheckChallenges, + TBool& aChallengeFound ) const + { + aChallengeFound = EFalse; + TBool match( EFalse ); + + if ( aMessage.HeaderCount( aHeaderName ) > 0 ) + { + TSglQueIter< CSIPHeaderBase > headers = aMessage.Headers( aHeaderName ); + while ( headers && !match ) + { + CSIPAuthHeaderBase* authHeader = + static_cast< CSIPAuthHeaderBase* >( headers++ ); + if ( !aCheckChallenges || + RSIPSecChallengeResolver::IsValidDigestChallenge( + *authHeader ) ) + { + aChallengeFound = ETrue; + match = CompareAKARealm( *authHeader, + aRealm, + aAlgorithm, + aDefaultAlgorithm ); + } + } + } + return match; + } + +// ----------------------------------------------------------------------------- +// CSIPSecDigestCache::CompareAKARealm +// aAlgorithm may change in this function, but caller's algorithm must not. +// ----------------------------------------------------------------------------- +// +TBool CSIPSecDigestCache::CompareAKARealm( CSIPAuthHeaderBase& aHeader, + const TDesC8& aCachedRealm, + RStringF aAlgorithm, + RStringF aDefaultAlgorithm ) const + { + RSIPSecChallengeResolver::SelectAlgorithm( aHeader, + aDefaultAlgorithm, + aAlgorithm ); + return ( TSIPSecDigestContext::GetDesParam( aHeader, + SipStrConsts::ERealm ).Compare( aCachedRealm ) == 0 ) && + ( aAlgorithm == SIPStrings::StringF( SipStrConsts::EAKAv1MD5 ) ); + } + +// ----------------------------------------------------------------------------- +// CSIPSecDigestCache::ChangeRecordUserIfNeeded +// If none of the entries in iProxyList or iEndpointList that point to aRecord, +// have the same SIPSec user as the aRecord, change aRecord's SIPSec user to be +// any of the referring entries' SIPSec user. +// ----------------------------------------------------------------------------- +// +void CSIPSecDigestCache::ChangeRecordUserIfNeeded( CSIPSecUserRecord& aRecord, + const MSIPSecUser& aUser ) + { + // Do not compare trusted user + if ( &aRecord.User() == &aUser ) + { + // Loop both proxy and endpoint caches. + // iProxyListIter and iEndpointListIter are already used by the code + // that calls ChangeRecordUserIfNeeded(), so use new iterators. + TSIPSecDigestCacheEntryIterator proxyListIter( iProxyList ); + TSIPSecDigestCacheEntryIterator endpointListIter( iEndpointList ); + TSIPSecDigestCacheIterator cacheIterator; + // Initialize iterators + proxyListIter.SetToFirst(); + endpointListIter.SetToFirst(); + cacheIterator.iList.Reset(); + cacheIterator.iList.AddLast( proxyListIter ); + cacheIterator.iList.AddLast( endpointListIter ); + cacheIterator.iListIterator.SetToFirst(); + + const MSIPSecUser* sipSecUser( NULL ); + CSIPSecDigestCacheEntry* entry( NULL ); + while ( ( entry = cacheIterator.Next() ) != NULL ) + { + if ( entry->HoldsUserData( aRecord ) ) + { + if ( &entry->SIPSecUser() == &aUser ) + { + return; // Same SIPSec user, no action needed + } + else + { + sipSecUser = &entry->SIPSecUser(); + } + } + } + + // Original SIPSec user no longer uses aRecord. + // Change SIPSec user to one of those still using it. + __ASSERT_DEBUG( sipSecUser != NULL, + User::Panic( _L( "DigestCache:ChangeRecUser" ), + KErrNotFound ) ); + if ( sipSecUser ) + { + aRecord.SetUser( *sipSecUser ); + } + } + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ---------------------------------------------------------------------------- +// TSIPSecDigestCacheEntryIterator::TSIPSecDigestCacheEntryIterator +// ---------------------------------------------------------------------------- +// +TSIPSecDigestCacheEntryIterator::TSIPSecDigestCacheEntryIterator( + TSglQue& aList ) : + TSglQueIter( aList ), + iLink() + { + SetToFirst(); + } + +// ---------------------------------------------------------------------------- +// TSIPSecDigestCacheEntryIterator::Next +// Return the next matching entry in the cache. +// ---------------------------------------------------------------------------- +// +CSIPSecDigestCacheEntry* +TSIPSecDigestCacheEntryIterator::Next( TSIPSecPluginContext& aContext ) + { + CSIPSecDigestCacheEntry* entry( NULL ); + + while ( ( entry = Next() ) != NULL ) + { + if ( entry->Match( aContext ) ) + { + return entry; + } + } + + return NULL; + } + +// ---------------------------------------------------------------------------- +// TSIPSecDigestCacheEntryIterator::Next +// ---------------------------------------------------------------------------- +// +CSIPSecDigestCacheEntry* TSIPSecDigestCacheEntryIterator::Next() + { + return ( *this )++; + } + + + +// ============================ MEMBER FUNCTIONS =============================== + +// ---------------------------------------------------------------------------- +// TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator +// ---------------------------------------------------------------------------- +// +TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator() : + iList( TSIPSecDigestCacheEntryIterator::iSIPSecOffset ), + iListIterator( TSglQueIter( iList ) ), + iContext( NULL ) + { + } + +// ---------------------------------------------------------------------------- +// TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator +// ---------------------------------------------------------------------------- +// +TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator( + TSIPSecPluginContext& aContext ) : + iList( TSIPSecDigestCacheEntryIterator::iSIPSecOffset ), + iListIterator( TSglQueIter( iList ) ), + iContext( &aContext ) + { + } + +// ---------------------------------------------------------------------------- +// TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator +// ---------------------------------------------------------------------------- +// +CSIPSecDigestCacheEntry* TSIPSecDigestCacheIterator::Next() + { + TSIPSecDigestCacheEntryIterator* iter( NULL ); + CSIPSecDigestCacheEntry* entry( NULL ); + + // Loop until an entry is found or both lists have been traversed + while ( !entry && ( iter = iListIterator ) != NULL ) + { + // Get next entry from current list + entry = iContext ? iter->Next( *iContext ) : iter->Next(); + + // If the current list has been exhausted, move to next list + if ( !entry ) + { + iter = ( iListIterator )++; + } + } + + return entry; + }