diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/TransactionUser/src/TransactionInfo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/SIP/TransactionUser/src/TransactionInfo.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,575 @@ +// 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 : TransactionInfo.cpp +// Part of : TransactionUser +// Version : SIP/6.0 +// + + + +#include "SipAssert.h" +#include "uricontainer.h" +#include "siptoheader.h" +#include "sipfromheader.h" +#include "sipviaheader.h" +#include "sipcallidheader.h" +#include "sipcseqheader.h" +#include "siprecordrouteheader.h" +#include "sipcontactheader.h" +#include "siprequest.h" +#include "sipstrings.h" +#include "sipstrconsts.h" + +#include "CUserAgent.h" +#include "TransactionInfo.h" +#include "CTransactionHeaders.h" +#include "SIPMessageUtility.h" + +// ----------------------------------------------------------------------------- +// CTransactionInfo::NewL +// ----------------------------------------------------------------------------- +// +CTransactionInfo* +CTransactionInfo::NewL(CTransactionBase::TTransactionType aType, TUint32 aIapId) + { + return new (ELeave) CTransactionInfo(aType, aIapId); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CTransactionInfo +// ----------------------------------------------------------------------------- +// +CTransactionInfo::CTransactionInfo(CTransactionBase::TTransactionType aType, + TUint32 aIapId) : + iTransactionType(aType), + iIapId(aIapId) +#ifdef CPPUNIT_TEST + , iViaHeaders(1), + iRecordRoute(1), + iContact(1) +#endif + { + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::~CTransactionInfo +// ----------------------------------------------------------------------------- +// +CTransactionInfo::~CTransactionInfo() + { + ClearMessageHeaders(); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::FreeContents +// UA owns transaction. Delete it only if it is detached from UA, or it differs +// from UA's transaction (=should be impossible). +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::FreeContents() + { + if (!iUserAgent || (iUserAgent->Transaction() != iTransaction)) + { + delete iTransaction; + iTransaction = NULL; + } + + delete iUserAgent; + iUserAgent = NULL; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::ClearMessageHeaders +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::ClearMessageHeaders() + { + delete iRequestURI; + iRequestURI = NULL; + + delete iTo; + iTo = NULL; + + delete iFrom; + iFrom = NULL; + + delete iCallID; + iCallID = NULL; + + iMethod.Close(); + iCSeq = 0; + iViaHeaders.ResetAndDestroy(); + iRecordRoute.ResetAndDestroy(); + iContact.ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::Receiver +// ----------------------------------------------------------------------------- +// +MTransactionReceiver* CTransactionInfo::Receiver() + { + if (iTransaction) + { + return iTransaction; + } + return iUserAgent; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::UserAgent +// ----------------------------------------------------------------------------- +// +CUserAgent* CTransactionInfo::UserAgent() + { + return iUserAgent; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::SetUserAgent +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::SetUserAgent(CUserAgent* aUserAgent) + { + iUserAgent = aUserAgent; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::SetTransaction +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::SetTransaction(CTransactionBase* aTransaction) + { + iTransaction = aTransaction; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::TransactionId +// ----------------------------------------------------------------------------- +// +TTransactionId CTransactionInfo::TransactionId() const + { + return iTransactionId; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::SetTransactionId +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::SetTransactionId(TTransactionId aTransactionId) + { + iTransactionId = aTransactionId; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::IapId +// ----------------------------------------------------------------------------- +// +TUint32 CTransactionInfo::IapId() const + { + return iIapId; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::TopVia +// ----------------------------------------------------------------------------- +// +CSIPViaHeader& CTransactionInfo::TopVia() const + { + __ASSERT_ALWAYS(iViaHeaders.Count() > 0, + User::Panic(_L("TaInfo:TopVia"), KErrNotFound)); + return *iViaHeaders[0]; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::UpdateMessageHeadersL +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::UpdateMessageHeadersL(CSIPMessage* aMsg) + { + if (aMsg) + { + ClearMessageHeaders(); + + if (aMsg->IsRequest()) + { + CURIContainer* uri = static_cast(aMsg)->RequestURI(); + if (uri) + { + iRequestURI = CURIContainer::NewL(*uri); + } + } + + iMethod.Close(); + iMethod = CSIPMessageUtility::MessageMethod(*aMsg).Copy(); + + iTo = static_cast + (CSIPMessageUtility::CopyHeaderFromMsgL(*aMsg, + SIPStrings::StringF(SipStrConsts::EToHeader))); + iFrom = static_cast + (CSIPMessageUtility::CopyHeaderFromMsgL(*aMsg, + SIPStrings::StringF(SipStrConsts::EFromHeader))); + iCallID = static_cast + (CSIPMessageUtility::CopyHeaderFromMsgL(*aMsg, + SIPStrings::StringF(SipStrConsts::ECallIDHeader))); + + if (aMsg->HasHeader(SIPStrings::StringF(SipStrConsts::ECSeqHeader))) + { + iCSeq = aMsg->CSeq()->Seq(); + } + + CopyViaHeadersFromMsgL(*aMsg); + } + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::UpdateToTagL +// Server transaction has checked there is no To-tag yet. +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::UpdateToTagL(RStringF aTag) + { + __SIP_ASSERT_LEAVE(iTo, KErrNotFound); + + RStringF tag = SIPStrings::StringF(SipStrConsts::ETag); + __SIP_ASSERT_LEAVE(!iTo->HasParam(tag), KErrAlreadyExists); + + iTo->SetParamL(tag, aTag); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CopyViaHeadersFromMsgL +// Sent requests have empty host part, but response matching won't use sent-by. +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::CopyViaHeadersFromMsgL(CSIPMessage& aMsg) + { + const RStringF KVia = SIPStrings::StringF(SipStrConsts::EViaHeader); + if (aMsg.HasHeader(KVia)) + { + iViaHeaders.ResetAndDestroy(); + + TSglQueIter iter = aMsg.Headers(KVia); + for (CSIPHeaderBase* header = iter++; header; header = iter++) + { + CSIPViaHeader* via = dynamic_cast(header->CloneL()); + CleanupStack::PushL(via); + iViaHeaders.AppendL(via); + CleanupStack::Pop(via); + } + } + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::StoreRecordRouteHeadersL +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::StoreRecordRouteHeadersL(CSIPRequest& aReq) + { + __SIP_ASSERT_LEAVE(iRecordRoute.Count() == 0, KErrAlreadyExists); + + const RStringF KRecordRoute = + SIPStrings::StringF(SipStrConsts::ERecordRouteHeader); + if (aReq.HasHeader(KRecordRoute)) + { + TSglQueIter iter = aReq.Headers(KRecordRoute); + for (CSIPHeaderBase* header = iter++; header; header = iter++) + { + CSIPRecordRouteHeader* rr = + static_cast(header->CloneL()); + CleanupStack::PushL(rr); + iRecordRoute.AppendL(rr); + CleanupStack::Pop(rr); + } + } + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::FreeRecordRouteHeaders +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::FreeRecordRouteHeaders() + { + iRecordRoute.ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::StoreContactHeadersL +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::StoreContactHeadersL(CSIPRequest& aReq) + { + __SIP_ASSERT_LEAVE(iContact.Count() == 0, KErrAlreadyExists); + + const RStringF KContact = SIPStrings::StringF(SipStrConsts::EContactHeader); + if (aReq.HasHeader(KContact)) + { + TSglQueIter iter = aReq.Headers(KContact); + for (CSIPHeaderBase* header = iter++; header; header = iter++) + { + CSIPContactHeader* contact = + dynamic_cast(header->CloneL()); + CleanupStack::PushL(contact); + iContact.AppendL(contact); + CleanupStack::Pop(contact); + } + } + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::FreeContactHeaders +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::FreeContactHeaders() + { + iContact.ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::RequiredHeadersPresent +// ----------------------------------------------------------------------------- +// +TBool CTransactionInfo::RequiredHeadersPresent() const + { + return iViaHeaders.Count() > 0 && iFrom && iTo && iCallID && MethodExists(); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::MethodExists +// ----------------------------------------------------------------------------- +// +TBool CTransactionInfo::MethodExists() const + { + return iMethod.DesC().Length() > 0; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CompareType +// ----------------------------------------------------------------------------- +// +TBool +CTransactionInfo::CompareType(CTransactionBase::TTransactionType aType) const + { + return aType == iTransactionType; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CompareMethod +// If the received message is ACK, iMethod should be INVITE. +// ----------------------------------------------------------------------------- +// +TBool CTransactionInfo::CompareMethod(RStringF aMsgMethod) const + { + if (aMsgMethod == SIPStrings::StringF(SipStrConsts::EAck)) + { + return iMethod == SIPStrings::StringF(SipStrConsts::EInvite); + } + + return aMsgMethod == iMethod; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CompareRequestLine +// Don't compare ACK's Request-URI, as it can be different than in INVITE. +// ----------------------------------------------------------------------------- +// +TBool CTransactionInfo::CompareRequestLine(const CURIContainer& aReqUri, + RStringF aMethod, + TBool aSearchCanceledUas) const + { + if (iRequestURI) + { + if (aMethod == SIPStrings::StringF(SipStrConsts::EAck)) + { + return CompareMethod(aMethod); + } + + if (aReqUri == *iRequestURI) + { + return (aSearchCanceledUas || CompareMethod(aMethod)); + } + } + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CompareHeaders +// If ACK, don't compare top Via. +// ----------------------------------------------------------------------------- +// +TBool CTransactionInfo::CompareHeaders(CSIPRequest& aReq) const + { + __ASSERT_DEBUG(aReq.RequestURI() != NULL && + aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EViaHeader)) && + aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EFromHeader)) && + aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EToHeader)) && + aReq.HasHeader(SIPStrings::StringF(SipStrConsts::ECSeqHeader)) && + aReq.HasHeader(SIPStrings::StringF(SipStrConsts::ECallIDHeader)), + User::Panic(_L("CTaInfo:Compare aReq"), KErrArgument)); + __ASSERT_DEBUG(RequiredHeadersPresent(), + User::Panic(_L("CTaInfo:Compare headers not stored"), KErrArgument)); + + + + if (CSIPMessageUtility::CompareTags(*iTo, *aReq.To()) && + CSIPMessageUtility::CompareTags(*iFrom, *aReq.From()) && + *iCallID == *aReq.CallID() && + iCSeq == aReq.CSeq()->Seq()) + { + if(CSIPMessageUtility::IsAck(aReq)) + return ETrue; + else + { + CSIPViaHeader* topvia = CSIPMessageUtility::TopVia(aReq); + if (topvia) + return(*topvia == TopVia()); + } + } + return EFalse; + } + + +// ----------------------------------------------------------------------------- +// CTransactionInfo::IsMergedRequest +// aCSeqMethod can't be ACK, as stray ACKs are dropped. +// ----------------------------------------------------------------------------- +// +TBool CTransactionInfo::IsMergedRequest(const CUserAgent& aUserAgent, + CSIPFromHeader& aFrom, + CSIPCallIDHeader& aCallID, + TUint aCSeqNbr, + RStringF aCSeqMethod) const + { + __ASSERT_DEBUG(aCSeqMethod != SIPStrings::StringF(SipStrConsts::EAck), + User::Panic(_L("CTaInfo:IsMergedRequest"), KErrArgument)); + return (iUserAgent != &aUserAgent) && + iFrom && + iCallID && + MethodExists() && + CSIPMessageUtility::CompareTags(aFrom, *iFrom) && + (aCallID == *iCallID) && + (aCSeqNbr == iCSeq) && + iUserAgent->IsUAS() && // Allow application to send request to itself + // Allow receiving CANCEL + (iMethod != SIPStrings::StringF(SipStrConsts::EInvite) || + aCSeqMethod != SIPStrings::StringF(SipStrConsts::ECancel)); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::TransactionHeadersL +// ----------------------------------------------------------------------------- +// +MTransactionHeaders* CTransactionInfo::TransactionHeadersL() + { + return CTransactionHeaders::NewL(iRequestURI, + iTo, + iFrom, + iCallID, + iCSeq, + iRecordRoute, + iContact); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CopyToFromCallIDCSeqToMsgL +// Copy headers only if they don't exist. +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::CopyToFromCallIDCSeqToMsgL(CSIPMessage& aMsg) const + { + if (iTo && !aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::EToHeader))) + { + CSIPToHeader* to = CSIPToHeader::NewLC(*iTo); + aMsg.AddHeaderL(to); + CleanupStack::Pop(to); + } + + if (iFrom && + !aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::EFromHeader))) + { + CSIPFromHeader* from = CSIPFromHeader::NewLC(*iFrom); + aMsg.AddHeaderL(from); + CleanupStack::Pop(from); + } + + if (iCallID && + !aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::ECallIDHeader))) + { + CSIPCallIDHeader* callID = + static_cast(iCallID->CloneL()); + CleanupStack::PushL(callID); + aMsg.AddHeaderL(callID); + CleanupStack::Pop(callID); + } + + CSIPMessageUtility::FillCSeqL(aMsg, + iCSeq, + aMsg.IsRequest() ? static_cast(aMsg).Method() : iMethod); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CopyViaHeadersToMsgL +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::CopyViaHeadersToMsgL(CSIPMessage& aMsg) const + { + for (TInt i = 0; i < iViaHeaders.Count(); ++i) + { + CSIPViaHeader* via = + static_cast(iViaHeaders[i]->CloneL()); + CleanupStack::PushL(via); + aMsg.AddHeaderL(via); + CleanupStack::Pop(via); + } + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::CopyRequestUriToRequestL +// ----------------------------------------------------------------------------- +// +void CTransactionInfo::CopyRequestUriToRequestL(CSIPRequest& aReq) const + { + __SIP_ASSERT_LEAVE(iRequestURI, KErrNotFound); + + CURIContainer* reqUri = CURIContainer::NewLC(*iRequestURI); + aReq.SetRequestURIL(reqUri); + CleanupStack::Pop(reqUri); + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::BuildRequestFromStoredInfoL +// ----------------------------------------------------------------------------- +// +CSIPRequest* CTransactionInfo::BuildRequestFromStoredInfoL() const + { + CSIPRequest* req(NULL); + if (iRequestURI && iTo && iFrom && MethodExists()) + { + req = CSIPRequest::NewLC(iMethod); + CopyToFromCallIDCSeqToMsgL(*req); + CopyRequestUriToRequestL(*req); + CleanupStack::Pop(req); + } + return req; + } + +// ----------------------------------------------------------------------------- +// CTransactionInfo::RequestMethod +// ----------------------------------------------------------------------------- +// +RStringF CTransactionInfo::RequestMethod() const + { + return iMethod; + }