realtimenetprots/sipfw/SIP/TransactionUser/src/TransactionStore.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/TransactionUser/src/TransactionStore.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,908 @@
+// 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          : TransactionStore.cpp
+// Part of       : TransactionUser
+// Version       : SIP/6.0
+//
+
+
+
+#include <centralrepository.h>
+#include "sipprivatecrkeys.h"
+#include "SipAssert.h"
+#include "sipfromheader.h"
+#include "sipviaheader.h"
+#include "sipcseqheader.h"
+#include "siphostport.h"
+#include "siprequest.h"
+#include "sipresponse.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+
+#include "CTransactionStore.h"
+#include "InviteUAS.h"
+#include "SIPMessageUtility.h"
+
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::NewL
+// -----------------------------------------------------------------------------
+//
+CTransactionStore* CTransactionStore::NewL()
+	{	
+	CTransactionStore* self = new (ELeave) CTransactionStore();
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::CTransactionStore
+// -----------------------------------------------------------------------------
+//
+CTransactionStore::CTransactionStore() :
+	iList(_FOFF(CTransactionInfo, iLink)),
+	iTransactionIdCounter(KMaxTransactionId),
+	iMaxServerTransactions(KMaxTInt)
+	{
+	}
+// -----------------------------------------------------------------------------
+// CTransactionStore::ConstructL
+// Read upper limit of simultaneous server transactions from central repository
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::ConstructL()
+	{
+	TInt maxServerTransactions(0);
+	CRepository* repository = CRepository::NewL(KCRUidSIP);
+	if ((repository->Get(KSIPMaxPendingServerTransactions,
+						 maxServerTransactions) == KErrNone) &&
+		maxServerTransactions >= 0)
+		{
+		iMaxServerTransactions = maxServerTransactions;
+		}
+	delete repository;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::~CTransactionStore
+// -----------------------------------------------------------------------------
+//
+CTransactionStore::~CTransactionStore()
+	{
+	CTransactionInfo* taInfo = iList.First();
+	while (iList.IsFirst(taInfo) && !iList.IsEmpty())
+		{
+		DeleteItem(taInfo);		
+		taInfo = iList.First();
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::DeleteItem
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::DeleteItem(CTransactionInfo* aItem)
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_RETURN(aItem, KErrArgument);
+	
+	RemoveListItem(*aItem);
+	aItem->FreeContents();
+	delete aItem;
+	
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::NewTransactionId
+// -----------------------------------------------------------------------------
+//
+TTransactionId CTransactionStore::NewTransactionId()
+	{
+	__TEST_INVARIANT;
+
+	if (iTransactionIdCounter < KMaxTransactionId)
+		{
+		++iTransactionIdCounter;
+		}
+	else
+		{
+		iTransactionIdCounter = KMinTransactionId;
+		}
+
+	__TEST_INVARIANT;
+	return iTransactionIdCounter;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::AddL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::AddL(TTransactionId aTransactionId,
+							 CUserAgent* aUserAgent,
+							 CTransactionBase* aTransaction,
+							 CSIPMessage* aMsg,
+							 CTransactionBase::TTransactionType aType)
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_LEAVE(aTransactionId != KEmptyTransactionId, KErrArgument);
+	__SIP_ASSERT_LEAVE(aUserAgent, KErrArgument);
+
+    CTransactionInfo* newItem =
+    	CTransactionInfo::NewL(aType, aUserAgent->TransportParams().IapId());
+    CleanupStack::PushL(newItem);
+	newItem->UpdateMessageHeadersL(aMsg);
+    CleanupStack::Pop(newItem);
+	if (aUserAgent->IsUAS())
+		{
+		++iServerTransactionCount;
+		}
+
+    iList.AddLast(*newItem);
+
+	// Attach UA when can't leave
+	newItem->SetUserAgent(aUserAgent);
+	newItem->SetTransaction(aTransaction);
+	newItem->SetTransactionId(aTransactionId);
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::StoreRecordRouteHeadersL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::StoreRecordRouteHeadersL(TTransactionId aTransactionId,
+												 CSIPRequest& aReq)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+    __SIP_ASSERT_LEAVE(taInfo, KErrNotFound);
+	taInfo->StoreRecordRouteHeadersL(aReq);
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::FreeRecordRouteHeaders
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::FreeRecordRouteHeaders(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	__SIP_ASSERT_RETURN(taInfo, KErrNotFound);
+	taInfo->FreeRecordRouteHeaders();
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::StoreContactHeadersL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::StoreContactHeadersL(TTransactionId aTransactionId,
+											 CSIPRequest& aReq)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	__SIP_ASSERT_LEAVE(taInfo, KErrNotFound);
+	taInfo->StoreContactHeadersL(aReq);
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::FreeContactHeaders
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::FreeContactHeaders(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	__SIP_ASSERT_RETURN(taInfo, KErrNotFound);
+	taInfo->FreeContactHeaders();
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::Search
+// UAC sets the magic cookie, so a response without it is broken and dropped.
+// Incoming request without branch or ACK to a 2xx: search using headers.
+// -----------------------------------------------------------------------------
+//
+MReceiverObserver* CTransactionStore::Search(CSIPMessage& aMsg)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionBase::TTransactionType taType =
+        CSIPMessageUtility::TransactionType(aMsg, ETrue);
+
+    if (CSIPMessageUtility::HasViaMagicCookie(aMsg))
+        {
+        MReceiverObserver* receiver = SearchByBranch(aMsg, taType, NULL);
+        if (receiver || !CSIPMessageUtility::IsAck(aMsg))
+            {
+            __TEST_INVARIANT;
+			return receiver;
+            }
+        }
+
+	if (aMsg.IsRequest())
+		{
+		return SearchServerByHeaders(
+            static_cast<CSIPRequest&>(aMsg), taType, NULL);
+		}
+
+    __TEST_INVARIANT;
+	return NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::SearchUasToCancel
+// -----------------------------------------------------------------------------
+//
+CUserAgentServer*
+CTransactionStore::SearchUasToCancel(CSIPRequest& aCancel,
+									 const CUserAgent& aCancelUAS)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionBase::TTransactionType taType =
+        CSIPMessageUtility::TransactionType(aCancel, ETrue);
+	MReceiverObserver* receiver(NULL);
+
+	if (CSIPMessageUtility::HasViaMagicCookie(aCancel))
+		{
+		receiver = SearchByBranch(aCancel, taType, &aCancelUAS);
+		}
+	else
+		{
+		receiver = SearchServerByHeaders(aCancel, taType, &aCancelUAS);
+		}
+
+	CUserAgentServer* uas = static_cast<CUserAgentServer*>(receiver);
+
+	// Must not return the same UAS that initiated the search
+	__ASSERT_DEBUG(uas != &aCancelUAS,
+				   User::Panic(_L("TaStore:SearchUasToCancel"), KErrGeneral));
+	__TEST_INVARIANT;
+	return uas;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::SearchServerByHeaders
+// Use CompareTransactionTypes before CompareHeaders, so CompareHeaders is not
+// used on UAC's taInfo as it has no sent-by part in Via. UAC uses magic cookie.
+// -----------------------------------------------------------------------------
+//
+MReceiverObserver*
+CTransactionStore::SearchServerByHeaders(CSIPRequest& aReq,
+									 CTransactionBase::TTransactionType aType,
+									 const CUserAgent* aUserAgent)
+	{
+	__TEST_INVARIANT;
+
+	MReceiverObserver* res(NULL);
+	if (RequiredHeadersPresent(aReq))
+		{
+	    TBool searchCanceledUas = (aUserAgent != NULL);
+	    TSglQueIter<CTransactionInfo> iter(iList);
+
+	    for (CTransactionInfo* taInfo = iter++; !res && taInfo; taInfo = iter++)
+		    {
+		    if (taInfo->RequiredHeadersPresent() &&
+			    CompareTransactionTypes(*taInfo, aType, searchCanceledUas) &&
+				taInfo->CompareHeaders(aReq) &&
+				taInfo->CompareRequestLine(*(aReq.RequestURI()),
+										   aReq.Method(),
+										   searchCanceledUas))
+				{
+				res = CheckResult(*taInfo, aUserAgent);
+				}
+		    }
+        }
+
+	__TEST_INVARIANT;
+	return res;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::RequiredHeadersPresent
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionStore::RequiredHeadersPresent(CSIPMessage& aMsg) const
+	{
+	__TEST_INVARIANT;
+	return aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::EViaHeader))  &&
+		   aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::EFromHeader)) &&
+		   aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::EToHeader))   &&
+		   aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::ECSeqHeader)) &&
+		   (!aMsg.IsRequest() || static_cast<CSIPRequest&>(aMsg).RequestURI());
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::SearchByBranch
+// -----------------------------------------------------------------------------
+//
+MReceiverObserver*
+CTransactionStore::SearchByBranch(CSIPMessage& aMsg,
+								  CTransactionBase::TTransactionType aType,
+								  const CUserAgent* aUserAgent)
+	{
+	__TEST_INVARIANT;
+
+    CSIPViaHeader* topVia = CSIPMessageUtility::TopVia(aMsg);
+    __ASSERT_DEBUG(topVia != NULL,
+        		   User::Panic(_L("TaStore:SearchByBranch"), KErrArgument));
+
+    TBool searchCanceledUas = (aUserAgent != NULL);
+	RStringF method = CSIPMessageUtility::MessageMethod(aMsg);
+	RStringF branch = SIPStrings::StringF(SipStrConsts::EBranch);		
+
+	MReceiverObserver* result(NULL);
+	TSglQueIter<CTransactionInfo> iter(iList);
+	for (CTransactionInfo* taInfo = iter++; taInfo && !result; taInfo = iter++)
+		{
+		// Skip transactions not associated with a SIP request.
+        // Type must match, e.g. a client transaction receives only responses.
+		if (taInfo->RequiredHeadersPresent() &&
+			CompareTransactionTypes(*taInfo, aType, searchCanceledUas))
+			{
+			CSIPViaHeader& storedVia = taInfo->TopVia();
+			if (storedVia.HasParam(branch) &&
+				(storedVia.ParamValue(branch) == topVia->ParamValue(branch)) &&
+				(searchCanceledUas || taInfo->CompareMethod(method)) &&
+				(aType == CTransactionBase::KClientTransaction ||
+				 aType == CTransactionBase::KClientInviteTransaction ||
+                 // Server transaction: sent-by of top via must match.
+                 // Client transaction: sent-by can be missing from storedVia.
+				 (storedVia.SentByHostPort() == topVia->SentByHostPort())))
+				{
+				result = IgnoreAckTo2xx(aMsg, *taInfo,	aUserAgent);
+				}
+			}
+		}
+
+	__TEST_INVARIANT;
+	return result;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::CompareTransactionTypes
+// If searching UAS to cancel, accept only server transactions.
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionStore::CompareTransactionTypes(const CTransactionInfo& aInfo,
+								   CTransactionBase::TTransactionType aType,
+								   TBool aSearchCanceledUas) const
+	{
+    __TEST_INVARIANT;
+
+	if (aSearchCanceledUas)
+		{
+		__ASSERT_DEBUG(aType == CTransactionBase::KServerTransaction,
+					   User::Panic(_L("TaStore:CompTaTypes"), KErrArgument));		
+		return aInfo.CompareType(CTransactionBase::KServerTransaction) ||
+               aInfo.CompareType(CTransactionBase::KServerInviteTransaction);
+		}
+
+	return aInfo.CompareType(aType);
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::IgnoreAckTo2xx
+// Ignore Via branch of ACK to a 2xx. INVITE may've forked, one UAS sent 2xx,
+// other 4xx. Even if UAC sends ACK to both with a same branch as in INVITE, UAS
+// must ignore the ACK targeted to the other UAS. To-tag is the difference.
+// -----------------------------------------------------------------------------
+//
+MReceiverObserver*
+CTransactionStore::IgnoreAckTo2xx(const CSIPMessage& aMsg,
+                                  CTransactionInfo& aInfo,
+								  const CUserAgent* aUserAgent) const
+    {
+    __TEST_INVARIANT;
+
+	if (CSIPMessageUtility::IsAck(aMsg) && !aUserAgent && aInfo.UserAgent())
+        {
+        // aMsg is ACK so UA must be InviteUAS
+        __ASSERT_DEBUG(aInfo.UserAgent()->IsUAS() &&
+            aInfo.CompareType(CTransactionBase::KServerInviteTransaction),
+            User::Panic(_L("TaStore:IgnoreAckTo2xx"), KErrGeneral));
+
+        if (CInviteUAS::Ptr(*(aInfo.UserAgent())).IsSending2xx())
+            {
+            return NULL;
+            }
+        }
+
+    return CheckResult(aInfo, aUserAgent);
+    }
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::CheckResult
+// -----------------------------------------------------------------------------
+//
+MReceiverObserver*
+CTransactionStore::CheckResult(CTransactionInfo& aInfo,
+							   const CUserAgent* aUserAgent) const
+	{
+    __TEST_INVARIANT;
+
+	if (!aUserAgent)
+		{
+		__ASSERT_DEBUG(aInfo.Receiver(),
+					   User::Panic(_L("TaStore:ChkResult"), KErrNotFound));
+		return aInfo.Receiver();
+		}
+
+	// Ignore result if it is the same UA that makes the search
+    if (aInfo.UserAgent() == aUserAgent)
+        {
+        return NULL;
+        }
+	return aInfo.UserAgent();
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::SearchById
+// -----------------------------------------------------------------------------
+//
+CUserAgent* CTransactionStore::SearchById(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	if (taInfo)
+		{
+		__ASSERT_DEBUG(taInfo->UserAgent(),
+					   User::Panic(_L("TaStore:SearchById"), KErrNotFound));
+		return taInfo->UserAgent();
+		}
+
+	return NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::FindTransactionInfo
+// -----------------------------------------------------------------------------
+//
+CTransactionInfo*
+CTransactionStore::FindTransactionInfo(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+    __ASSERT_DEBUG(aTransactionId != KEmptyTransactionId,
+        		   User::Panic(_L("TaStore:FindTaInfo"), KErrArgument));
+
+    TSglQueIter<CTransactionInfo> iter(iList);
+    for (CTransactionInfo* taInfo = iter++; taInfo; taInfo = iter++)
+    	{
+    	if (taInfo->TransactionId() == aTransactionId)
+			{
+			__TEST_INVARIANT;
+			return taInfo;
+			}
+    	if (taInfo->TransactionId() == KEmptyTransactionId)
+			{
+            // TransactionInfo marked for deletion. Delete it.
+			DeleteItem(taInfo);			
+			}
+    	}
+
+	__TEST_INVARIANT;
+	return NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::IcmpErrorL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::IcmpErrorL(const TInetAddr& aAddress,
+								   CSipConnectionMgr::TICMPError aError)
+	{
+	__TEST_INVARIANT;
+
+	TSglQueIter<CTransactionInfo> iter(iList);
+	for (CTransactionInfo* taInfo = iter++; taInfo; taInfo = iter++)
+		{
+		if (taInfo->Receiver())
+			{
+			taInfo->Receiver()->IcmpErrorL(aAddress, aError);
+			}
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::ClearUserAgent
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::ClearUserAgent(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	if (taInfo)
+		{
+		taInfo->SetUserAgent(NULL);
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::ClearTransaction
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::ClearTransaction(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	if (taInfo)
+		{
+		taInfo->SetTransaction(NULL);
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::UpdateTransactionId
+// -----------------------------------------------------------------------------
+//
+TInt CTransactionStore::UpdateTransactionId(TTransactionId aOldTransactionId,
+										    TTransactionId aNewTransactionId)
+	{
+	__TEST_INVARIANT;
+    __SIP_ASSERT_RETURN_VALUE(!(aOldTransactionId == aNewTransactionId),
+        					  KErrArgument);
+    TInt status(KErrNotFound);
+	CTransactionInfo* taInfo = FindTransactionInfo(aOldTransactionId);
+	if (taInfo)
+		{
+		taInfo->SetTransactionId(aNewTransactionId);
+		status = KErrNone;
+		}
+
+    __TEST_INVARIANT;
+	return status;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::UpdateL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::UpdateL(TTransactionId aTransactionId,
+								CTransactionBase* aTransaction,
+								CSIPMessage* aMsg)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	__ASSERT_ALWAYS(taInfo, User::Leave(KErrNotFound));
+	taInfo->SetTransaction(aTransaction);
+	taInfo->UpdateMessageHeadersL(aMsg);
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::UpdateToTagL
+// -----------------------------------------------------------------------------
+//
+void
+CTransactionStore::UpdateToTagL(TTransactionId aTransactionId, RStringF aTag)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	__ASSERT_ALWAYS(taInfo, User::Leave(KErrNotFound));
+	taInfo->UpdateToTagL(aTag);
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::Remove
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::Remove(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	if (taInfo)
+		{
+		RemoveListItem(*taInfo);
+		delete taInfo;
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::ClearTransactionOwner
+// -----------------------------------------------------------------------------
+//
+TInt
+CTransactionStore::ClearTransactionOwner(const MTransactionOwner* aObserver)
+	{
+	__TEST_INVARIANT;
+    __SIP_ASSERT_RETURN_VALUE(aObserver != NULL, KErrArgument);
+
+	TInt status(KErrNotFound);
+	TSglQueIter<CTransactionInfo> iter(iList);
+    CUserAgent* ua(NULL);
+
+	for (CTransactionInfo* taInfo = iter++; taInfo; taInfo = iter++)
+		{
+		ua = taInfo->UserAgent();
+		if (ua && ua->TransactionOwner() == aObserver)
+			{
+			ua->ClearTransactionOwner();
+			status = KErrNone;
+			// Continue the loop as many transactions may use the same aObserver
+			}
+		}
+
+	__TEST_INVARIANT;
+	return status;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::EndResolvingTransactions
+// Detached transactions (ua == NULL), are never resolving.
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::EndResolvingTransactions(TUint32 aIapId, TInt aReason)
+	{
+	__TEST_INVARIANT;
+
+	TSglQueIter<CTransactionInfo> iter(iList);
+	for (CTransactionInfo* taInfo = iter++; taInfo; taInfo = iter++)
+		{
+        CUserAgent* ua = taInfo->UserAgent();
+        if (ua && !ua->IsUAS())
+            {
+			if ((ua->TransportParams().IapId() == aIapId) && ua->IsResolving())
+				{
+				ua->Stop(aReason);
+				}
+            }
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::IsMergedRequest
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionStore::IsMergedRequest(const CUserAgent& aUserAgent,
+										 CSIPRequest& aReq)
+	{
+	__TEST_INVARIANT;
+
+	CSIPFromHeader* from = aReq.From();
+	__ASSERT_DEBUG(from, User::Panic(_L("TaStore:IsMerg !from"), KErrArgument));
+
+	if (!aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EFromHeader)) ||
+		!aReq.HasHeader(SIPStrings::StringF(SipStrConsts::ECallIDHeader)) ||
+		!aReq.HasHeader(SIPStrings::StringF(SipStrConsts::ECSeqHeader)) ||
+		!from->HasParam(SIPStrings::StringF(SipStrConsts::ETag)))
+		{
+		return EFalse;
+		}
+
+    CSIPCSeqHeader* cseq = aReq.CSeq();
+    __ASSERT_DEBUG(cseq, User::Panic(_L("TaStore:IsMerg !cseq"), KErrArgument));
+
+	TBool merged(EFalse);
+	TSglQueIter<CTransactionInfo> iter(iList);
+	for (CTransactionInfo* taInfo = iter++; taInfo && !merged; taInfo = iter++)
+		{
+		merged = taInfo->IsMergedRequest(aUserAgent,
+										 *from,
+										 *aReq.CallID(),
+										 cseq->Seq(),
+										 cseq->Method());
+		}
+
+	__TEST_INVARIANT;
+	return merged;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::CopyHeadersToResponseL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::CopyHeadersToResponseL(TTransactionId aTransactionId,
+											   CSIPResponse& aResp)
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_RETURN(aTransactionId != KEmptyTransactionId, KErrArgument);
+	__SIP_ASSERT_RETURN(
+		!aResp.HasHeader(SIPStrings::StringF(SipStrConsts::EViaHeader)),
+		KErrArgument);
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	if (taInfo)
+		{
+		taInfo->CopyToFromCallIDCSeqToMsgL(aResp);
+		taInfo->CopyViaHeadersToMsgL(aResp);
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::CopyHeadersToRequestL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::CopyHeadersToRequestL(TTransactionId aTransactionId,
+										      CSIPRequest& aReq,
+											  TBool aCopyRequestURI,
+										      TBool aCopyViaHeaders)
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_LEAVE(aTransactionId != KEmptyTransactionId, KErrArgument);
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	if (taInfo)
+		{
+		taInfo->CopyToFromCallIDCSeqToMsgL(aReq);
+
+		if (aCopyRequestURI)
+			{
+			taInfo->CopyRequestUriToRequestL(aReq);
+			}
+
+		if (aCopyViaHeaders)
+			{
+			taInfo->CopyViaHeadersToMsgL(aReq);
+			}
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::TransactionHeadersL
+// -----------------------------------------------------------------------------
+//
+MTransactionHeaders*
+CTransactionStore::TransactionHeadersL(TTransactionId aTransactionId)
+	{
+	__TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	if (taInfo)
+		{
+		return taInfo->TransactionHeadersL();
+		}
+	return NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::RandomTaInfoL
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::RandomTaInfoL(TTransactionId& aTaId,
+								      CUserAgent** aUserAgent,
+								      CSIPMessage** aMsg)
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_LEAVE(aUserAgent && aMsg, KErrArgument);
+
+	TSglQueIter<CTransactionInfo> iter(iList);
+	for (CTransactionInfo* taInfo = iter++; taInfo; taInfo = iter++)
+		{
+		if (aTaId == KEmptyTransactionId)
+			{
+			aTaId = taInfo->TransactionId();
+			}
+
+		if (taInfo->UserAgent())
+			{
+			*aUserAgent = taInfo->UserAgent();
+			*aMsg = taInfo->BuildRequestFromStoredInfoL();
+
+            __TEST_INVARIANT;
+			return;
+			}
+		}
+
+    __TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::RequestMethod
+// -----------------------------------------------------------------------------
+//
+RStringF CTransactionStore::RequestMethod(TTransactionId aTransactionId)
+	{
+    __TEST_INVARIANT;
+
+	CTransactionInfo* taInfo = FindTransactionInfo(aTransactionId);
+	__ASSERT_DEBUG(taInfo, User::Panic(_L("TaStore:ReqMethod"), KErrNotFound));
+	return taInfo->RequestMethod();
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::RemoveItemsByIapId
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::RemoveItemsByIapId(TUint32 aIapId)
+    {
+    __TEST_INVARIANT;
+
+	TSglQueIter<CTransactionInfo> iter(iList);
+    for (CTransactionInfo* taInfo = iter++; taInfo; taInfo = iter++)
+        {
+        if (taInfo->IapId() == aIapId)
+            {
+            DeleteItem(taInfo);
+            }
+        }
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::AllowMoreServerTransactions
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionStore::AllowMoreServerTransactions() const
+	{
+	__TEST_INVARIANT;
+	return iServerTransactionCount < iMaxServerTransactions;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionStore::RemoveListItem
+// -----------------------------------------------------------------------------
+//
+void CTransactionStore::RemoveListItem(CTransactionInfo& aItem)
+	{
+	__TEST_INVARIANT;
+	if (aItem.CompareType(CTransactionBase::KServerTransaction) ||
+        aItem.CompareType(CTransactionBase::KServerInviteTransaction))
+		{
+		--iServerTransactionCount;
+		}
+	iList.Remove(aItem);
+	__TEST_INVARIANT;
+	}
+// CTransactionStore::__DbgTestInvariant
+// -----------------------------------------------------------------------------
+//
+
+void CTransactionStore::__DbgTestInvariant() const
+	{
+	if (iTransactionIdCounter < KMinTransactionId)
+		{
+		User::Invariant();
+		}
+	}
+