realtimenetprots/sipfw/SIP/SIPSec/IpSecPlugin/src/CSipSecAgreeContext.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/SIPSec/IpSecPlugin/src/CSipSecAgreeContext.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,589 @@
+// Copyright (c) 2006-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          : CSipSecAgreeContext.cpp
+// Part of       : SIPSec
+// Version       : SIP/5.0
+//
+
+
+
+#include "sipstrings.h"
+#include "siprequest.h"
+#include "sipresponse.h"
+#include "sipcseqheader.h"
+#include "MSIPTransportMgr.h"
+#include "MIpSecMechanismParams.h"
+#include "MSIPSecSecurityMechanismObserver.h"
+#include "CSipSecAgreeRecord.h"
+#include "CSipSecAgreeContext.h"
+#include "SipSecUtils.h"
+
+#ifdef CPPUNIT_TEST
+#include "CActiveObjController1.h"
+#endif
+
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::NewL
+// ----------------------------------------------------------------------------
+//
+CSipSecAgreeContext* CSipSecAgreeContext::NewL(
+	MIpSecMechanismParams& aParams,
+	TSIPTransportParams& aTransportParams,
+	CSIPResponse& aResponse,
+	CSIPRequest& aRequest,
+	TInetAddr& aRemoteAddress,
+	MSIPSecUser* aUser,
+	MSIPSecSecurityMechanismObserver& aObserver,
+	RPointerArray<CState>& aStates )	
+	{
+	CSipSecAgreeContext* 
+		self = CSipSecAgreeContext::NewLC( aParams,
+		                                   aTransportParams,
+		                                   aResponse,
+		                                   aRequest,
+										   aRemoteAddress,
+										   aUser,
+										   aObserver,
+										   aStates );
+	CleanupStack::Pop( self );
+	return self;
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::NewLC
+// ----------------------------------------------------------------------------
+//
+CSipSecAgreeContext* CSipSecAgreeContext::NewLC(
+	MIpSecMechanismParams& aParams,
+	TSIPTransportParams& aTransportParams,
+	CSIPResponse& aResponse,
+	CSIPRequest& aRequest,
+	TInetAddr& aRemoteAddress,
+	MSIPSecUser* aUser,
+	MSIPSecSecurityMechanismObserver& aObserver,
+	RPointerArray<CState>& aStates )
+	{
+	CSipSecAgreeContext* self = 
+	    new ( ELeave ) CSipSecAgreeContext( aParams, aObserver, aStates );
+	CleanupStack::PushL(self);
+	self->ConstructL( aTransportParams,
+	                  aResponse,
+	                  aRequest,
+					  aRemoteAddress,
+					  aUser );
+	return self;
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::CSipSecAgreeContext
+// ----------------------------------------------------------------------------
+//
+CSipSecAgreeContext::CSipSecAgreeContext( 
+	MIpSecMechanismParams& aParams,
+	MSIPSecSecurityMechanismObserver& aObserver,
+	RPointerArray<CState>& aStates ) :
+	iParams( aParams ),
+	iObserver( &aObserver ),
+	iStates( aStates )
+#ifdef CPPUNIT_TEST
+    , iSecAgreeRecords( 1 )
+#endif
+	{
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::ConstructL
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::ConstructL( TSIPTransportParams& aTransportParams,
+								      CSIPResponse& aResponse,
+								      CSIPRequest& aRequest,
+									  TInetAddr& aRemoteAddress,
+									  MSIPSecUser* aUser )
+	{
+	User::LeaveIfError( iParams.TransportMan().GetLocalAddress(
+                                                aTransportParams.IapId(),
+                                                iLocalAddress ) );
+	iRemoteAddress = aRemoteAddress;
+	iSecUser = aUser;
+
+	CSipSecAgreeRecord* r =
+	    CSipSecAgreeRecord::NewLC( iStates, *this, aTransportParams );
+
+#ifdef CPPUNIT_TEST
+	iObjCtr = new ( ELeave ) CActiveObjController1();
+	iObjCtr->iContext = this;
+	iObjCtr->iRcrdCtrl1 = r->iObjCtr;
+	r->iObjCtr->iFeedBack = iObjCtr;
+#endif
+
+	r->Resp4xxL( aResponse, aRequest );
+	iSecAgreeRecords.AppendL( r );
+	CleanupStack::Pop( r );
+	}
+	
+// ----------------------------------------------------------------------------
+// Destructor
+// ----------------------------------------------------------------------------
+//
+CSipSecAgreeContext::~CSipSecAgreeContext()
+	{
+	iSecAgreeRecords.ResetAndDestroy();	
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::MechParams
+// ----------------------------------------------------------------------------
+//
+MIpSecMechanismParams& CSipSecAgreeContext::MechParams()
+	{
+	return iParams;
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::LocalAddress
+// ----------------------------------------------------------------------------
+//
+TInetAddr CSipSecAgreeContext::LocalAddress()
+	{
+	return iLocalAddress;
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::PolicyServer
+// ----------------------------------------------------------------------------
+//	
+RIpsecPolicyServ& CSipSecAgreeContext::PolicyServer()
+    {
+    return iParams.PolicyServer();
+    }
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::RemoteAddress
+// ----------------------------------------------------------------------------
+//  
+TInetAddr CSipSecAgreeContext::RemoteAddress()
+	{
+	return iRemoteAddress;
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::HasOnlyOneRecord
+// ----------------------------------------------------------------------------
+//
+TBool CSipSecAgreeContext::HasOnlyOneRecord() const
+	{
+	TInt pos( 0 );
+	return ( NextRecord( pos ) != NULL && !NextRecord( pos ) );
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::HasRecordInState
+// ----------------------------------------------------------------------------
+//
+TBool
+CSipSecAgreeContext::HasRecordInState( CState::TSecAgreeRecordState aState )
+	{	
+	TInt pos( 0 );
+	TBool found( EFalse );
+	CSipSecAgreeRecord* record = NextRecord( pos );
+	for ( ; !found && record; record = NextRecord( pos ) )
+		{
+		found = ( record->State() == aState );
+		}
+	return found;
+	}
+	
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::SaDeleted
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::SaDeleted( CSipSecAgreeRecord* aRecord )
+	{
+	DeleteRecord( aRecord );
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::SaCleared
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::SaCleared( CSipSecAgreeRecord* aRecord )
+	{
+	DeleteRecord( aRecord );
+	if ( iSecAgreeRecords.Count() == 0 )
+		{
+		iParams.ContextCleared( this );
+		}
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::SAReady
+// ----------------------------------------------------------------------------
+//	
+void CSipSecAgreeContext::SAReady( TBool aSuccess )
+    {
+    if ( iObserver )
+        {
+        iObserver->SAReady( aSuccess );
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::HasLongerLifetimeSA
+// ----------------------------------------------------------------------------
+//
+TBool
+CSipSecAgreeContext::HasLongerLifetimeSA( TUint aTimeToCompareInMillisecs,
+										  TUint& aLongerLifetimeInMillisecs )
+    {
+    // Compare only with "inuse" records
+    TBool found( EFalse );
+    TInt pos( 0 );
+	for ( CSipSecAgreeRecord* record = NextRecord( pos );
+		  !found && record;
+		  record = NextRecord( pos ) )	
+		{
+		TUint expiresAfter = record->ExpiresAfter();
+
+		if ( record->State() == CState::EInUse &&
+		     ( expiresAfter > aTimeToCompareInMillisecs ) )
+			{
+			aLongerLifetimeInMillisecs = expiresAfter;
+			found = ETrue;
+			}		
+		}
+	return found;
+    }
+	
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::HasSecUser
+// ----------------------------------------------------------------------------
+//
+TBool CSipSecAgreeContext::HasSecUser( const MSIPSecUser* aSecUser ) const
+	{
+	return aSecUser == iSecUser;
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::HasNextHop
+// Ignore context for which clearing has started.
+// ----------------------------------------------------------------------------
+//
+TBool CSipSecAgreeContext::HasNextHop( const TInetAddr& aNextHop ) const
+    {
+    return ( !aNextHop.IsWildAddr() &&
+    		 iRemoteAddress.Match( aNextHop ) &&
+    		 !iClearOrdered );
+    }
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::ApplyRulesL
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::ApplyRulesL( TSIPTransportParams& aTransportParams, 
+									   CSIPRequest& aRequest,
+									   const TDesC8& aOutboundProxy,
+									   MSIPSecUser* aUser )
+	{
+	TInt pos( 0 );
+	CSipSecAgreeRecord* record = NextRecord( pos );
+
+	if ( SipSecUtils::Match( SipStrConsts::ERegister, aRequest.Method() ) )
+		{
+		// Other MSIPSecUsers cannot use existing context (SA)
+		// for registration to the same outbound proxy.
+		__ASSERT_ALWAYS( HasSecUser( aUser ), User::Leave( KErrInUse ) );
+
+		for ( ; record; record = NextRecord( pos ) )
+			{
+			record->RegisterL( aTransportParams, aRequest, aOutboundProxy );
+			}
+		}
+	else
+		{
+		for ( ; record; record = NextRecord( pos ) )
+			{
+			record->ReguestL( aTransportParams, aRequest, aOutboundProxy );
+			}
+		}
+	}
+	
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::ApplyRulesL
+// IPSec is only interested on 401 and 200 responses
+// ----------------------------------------------------------------------------
+//	
+void CSipSecAgreeContext::ApplyRulesL( 
+	CSIPResponse& aResponse,
+	CSIPRequest& aRequest,
+	MSIPSecSecurityMechanismObserver& aObserver )
+	{
+	if ( aResponse.ResponseCode() == K401Response )
+		{
+		// First check if a new record must be created
+		CreateNewSecAgreeRecordIfNeededL();
+
+		TInt pos( 0 );		
+		for ( CSipSecAgreeRecord* record = NextRecord( pos );
+			  record;
+			  record = NextRecord( pos ) )
+			{
+			record->Resp4xxL( aResponse, aRequest );
+			}
+		iObserver = &aObserver;	
+		}
+	if ( aResponse.ResponseCode() == K200Response )
+		{
+		CSIPCSeqHeader* h = static_cast<CSIPCSeqHeader*>(
+			SipSecUtils::SingleHeader( aResponse, SipStrConsts::ECSeqHeader ) );
+		if ( h && h->Method() == _STRINGF( SipStrConsts::ERegister ) )
+			{
+			TInt pos( 0 );
+			for ( CSipSecAgreeRecord* record = NextRecord( pos );
+				  record;
+				  record = NextRecord( pos ) )
+				{
+				record->Resp2xxL( aResponse );
+				}
+			iObserver = &aObserver;
+			}
+		}
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::CreateNewSecAgreeRecordIfNeededL
+// Create new record if an existing record is in InUse, Deleting or Clearing
+// state. Deleting and Clearing states are included because in some very rare
+// scenario 4xx might be received before SA deletion is completed, and such
+// situation must not cause malfunction.
+//
+//
+// If two records exist already. Drop one of them by setting it obsolete.
+//
+// Selecting the record to be obsoleted:
+//   SA-1's state	  SA-2's state				  drop
+//   ------------     ------------                ----
+//   InUse      	  Tentative..PendingPolicy	  SA-2
+//   Old..Deleting	  InUse						  SA-1
+//
+// When 2xx is received, SA-1 enters "Old" and SA-2 enters "InUse",
+// so two records can't be in "InUse".
+//
+//
+// New record uses initially same transport params, as it must share protected
+// server port with old record. When new record is reserving transport,
+// transport params will be updated. New record derives Security-Client and
+// Security-Verify headers from response and corresponding request.
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::CreateNewSecAgreeRecordIfNeededL()
+	{
+	if ( HasRecordInState( CState::EInUse ) ||
+		 HasRecordInState( CState::EDeleting ) ||
+		 HasRecordInState( CState::EClearing ) )
+		{
+		if ( !HasOnlyOneRecord() )	
+			{			
+			TInt pos( 0 );
+			CSipSecAgreeRecord* rec = NextRecord( pos );
+			if(rec)
+			{
+			if ( rec->State() == CState::EInUse )
+				{
+				// Record is "in use", drop the other record
+				rec = NextRecord( pos );
+				if(rec)
+				{
+					__ASSERT_ALWAYS( rec->State() != CState::EInUse,
+							 	 User::Leave( KErrGeneral ) );
+				}
+				}
+			}
+			if(rec)
+			{
+				rec->SetObsoleteL();
+			}
+			}
+		TInt pos = 0;
+		CSipSecAgreeRecord* rec = NextRecord( pos );
+		__ASSERT_ALWAYS( rec, User::Leave( KErrNotFound ) );
+
+		CSipSecAgreeRecord*	newRecord =
+		    CSipSecAgreeRecord::NewLC( iStates, *this, rec->TransportParams() );
+
+#ifdef CPPUNIT_TEST
+	    if ( !rec->iObjCtr->iFeedBack->iRcrdCtrl2 )
+	    	{
+	    	rec->iObjCtr->iFeedBack->iRcrdCtrl2 = newRecord->iObjCtr;
+	    	}
+	    else if ( !rec->iObjCtr->iFeedBack->iRcrdCtrl3 )
+	    	{
+	    	rec->iObjCtr->iFeedBack->iRcrdCtrl3 = newRecord->iObjCtr;
+	    	}
+	    else if ( !rec->iObjCtr->iFeedBack->iRcrdCtrl4 )
+	    	{
+	    	rec->iObjCtr->iFeedBack->iRcrdCtrl4 = newRecord->iObjCtr;
+	    	}
+#endif
+		iSecAgreeRecords.AppendL( newRecord );
+		CleanupStack::Pop( newRecord );
+		}
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::ApplyRulesL
+// ----------------------------------------------------------------------------
+//	
+void CSipSecAgreeContext::ApplyRulesL( 
+	RPointerArray<CSIPSecurityVerifyHeader>& aSecurityVerify )
+	{
+	TInt pos( 0 );
+	CSipSecAgreeRecord* record( NULL );
+	while ( ( record = NextRecord( pos ) ) != NULL )
+		{
+		record->ProcessSecVerifyL( aSecurityVerify );
+		}
+	}
+	
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::SetAuthKeyL
+// ----------------------------------------------------------------------------
+//
+TBool CSipSecAgreeContext::SetAuthKeyL( const TDesC8& aAuthKey )
+	{
+	TBool ret( EFalse );
+	TInt pos( 0 );
+	CSipSecAgreeRecord* record( NULL );
+	while ( ( record = NextRecord( pos ) ) != NULL )
+		{
+		ret |= record->AuthKeyL( aAuthKey );
+		}
+	return ret;
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::AuthKeyFailedL
+// ----------------------------------------------------------------------------
+//	
+void CSipSecAgreeContext::AuthKeyFailedL()
+    {
+    // Reverse order since call might lead to deletion of record
+    TInt lastIndex( iSecAgreeRecords.Count() - 1 );
+    for ( TInt i = lastIndex; i >= 0; --i )
+		{
+		if ( !iSecAgreeRecords[ i ]->IsObsolete() )
+			{
+			iSecAgreeRecords[ i ]->AuthKeyFailedL();
+			}
+		}
+    }
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::ClearL
+// Affects also obsolete records.
+// ----------------------------------------------------------------------------
+//	
+void CSipSecAgreeContext::ClearL()
+	{	
+	iClearOrdered = ETrue;
+
+	// Reverse order since call might lead to deletion of record, also whole
+	// context (this) will be removed if clearing leads to immediate deletion
+	// of all records.
+    TInt lastIndex( iSecAgreeRecords.Count() - 1 );
+	for ( TInt i = lastIndex; i >= 0; i--  )
+		{
+		iSecAgreeRecords[ i ]->ClearSaL();
+		}
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::CancelPendingOps
+// Affects also obsolete records.
+// ----------------------------------------------------------------------------
+//   
+void CSipSecAgreeContext::CancelPendingOps(
+    const MSIPSecSecurityMechanismObserver* aObserver )
+    {
+    if ( iObserver && iObserver == aObserver )
+        {
+        // Observer cannot be used anymore
+        iObserver = NULL;
+        for ( TInt i = 0; i < iSecAgreeRecords.Count(); ++i )
+		    {
+		    iSecAgreeRecords[ i ]->CancelPendingOps();
+		    }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::SADBAddMsgReceived
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::SADBAddMsgReceived( TUint aMsgSeq, TInt aError )
+    {    
+    TInt pos( 0 );
+	CSipSecAgreeRecord* record( NULL );
+	while ( ( record = NextRecord( pos ) ) != NULL )	    
+        {
+        record->SADBAddMsgReceived( aMsgSeq, aError );
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::RemovalCompleted
+// Affects also obsolete records.
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::RemovalCompleted( TUint32 aTransportId )
+    {    
+    for ( TInt i = 0; i < iSecAgreeRecords.Count(); ++i  )
+        {
+        iSecAgreeRecords[ i ]->RemovalCompleted( aTransportId );
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::DeleteRecord
+// Affects also obsolete records.
+// ----------------------------------------------------------------------------
+//
+void CSipSecAgreeContext::DeleteRecord( CSipSecAgreeRecord* aRecord )
+	{
+	TInt i = iSecAgreeRecords.Find( aRecord );
+	iSecAgreeRecords.Remove( i );
+	iSecAgreeRecords.Compress();
+	delete aRecord;	
+	}
+
+// ----------------------------------------------------------------------------
+// CSipSecAgreeContext::NextRecord
+// ----------------------------------------------------------------------------
+//
+CSipSecAgreeRecord* CSipSecAgreeContext::NextRecord( TInt& aPos ) const
+	{
+	for ( TInt i = aPos; i < iSecAgreeRecords.Count(); ++i )
+		{
+		if ( !iSecAgreeRecords[ i ]->IsObsolete() )
+			{
+			// Set aPos point to next record
+			aPos = i + 1;
+			return iSecAgreeRecords[ i ];
+			}
+		}
+	return NULL;
+	}
+
+// End of File