realtimenetprots/sipfw/SIP/Transaction/src/InviteClientTa.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/Transaction/src/InviteClientTa.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,512 @@
+// 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          : InviteClientTa.cpp
+// Part of       : Transaction
+// Version       : SIP/5.0
+//
+
+
+
+#include "SipAssert.h"
+#include "siperr.h"
+#include "Lwtimer.h"
+#include "uricontainer.h"
+#include "sipcseqheader.h"
+#include "siprequest.h"
+#include "sipresponse.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+#include "TimerValues.h"
+#include "SIPMessageUtility.h"
+#include "SIPRequestUtility.h"
+
+#include "InviteClientTa.h"
+#include "Transmitter.h"
+#include "TransactionState.h"
+#include "TransactionTimer.h"
+#include "RestoreTransactionState.h"
+
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::NewL
+// -----------------------------------------------------------------------------
+//
+CInviteClientTransaction* CInviteClientTransaction::NewL(
+							CUserAgentBase& aUserAgent,
+							CTransmitter& aTransmitter,
+							MTimerManager& aTimers,
+							CTransactionState& aInitialState,
+							TTimerValues& aTimerValues,
+							MTransactionStore& aTransactionStore,
+							TBool aRetransmitInvite)
+	{
+	CInviteClientTransaction* self =
+        new (ELeave) CInviteClientTransaction(aUserAgent,							
+									          aTransmitter,
+									          aTimers,
+									          aInitialState,
+									          aTimerValues,
+									          aTransactionStore,
+									          aRetransmitInvite);
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::CInviteClientTransaction
+// -----------------------------------------------------------------------------
+//
+CInviteClientTransaction::CInviteClientTransaction(
+						CUserAgentBase& aUserAgent,
+						CTransmitter& aTransmitter,
+						MTimerManager& aTimers,
+						CTransactionState& aInitialState,
+						TTimerValues& aTimerValues,
+						MTransactionStore& aTransactionStore,
+						TBool aRetransmitInvite) :
+	CClientTransaction(aUserAgent,
+					   aTransmitter,
+					   aTimers,
+					   aInitialState,
+					   aTimerValues,
+					   aTransactionStore),
+	iRetransmitInvite(aRetransmitInvite),iDTimerErrCode(KErrNone)
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::~CInviteClientTransaction
+// -----------------------------------------------------------------------------
+//
+CInviteClientTransaction::~CInviteClientTransaction()
+	{
+    //Scope operator to silence lint warning
+    CInviteClientTransaction::CancelAllTimers();
+
+	if (iTaOwnsRequest)
+		{
+		delete iOutgoingMsg;
+		}
+
+	//CInviteClientTransaction can own iTransmitter
+	if (iDeleteMgr)
+		{
+		delete iTransmitter;
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::IsInviteTransaction
+// -----------------------------------------------------------------------------
+//
+TBool CInviteClientTransaction::IsInviteTransaction() const
+	{
+	return ETrue;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::ReceiveResponseL
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::ReceiveResponseL(CSIPResponse* aResponse,
+									const CTransactionState& aCurrent,
+                                    const CTransactionState& aCompleted,
+                                    CTransactionTimer* aTimer,
+                          			CTransactionTimer* aTimer2)
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_LEAVE(aResponse, KErrArgument);
+
+	CSIPRequest* ack = NULL;
+	TBool isErrResponse = aResponse->IsErrorResponse();
+	if ( isErrResponse )
+	    {
+	    ack = MakeAckLC(*aResponse);
+        ChangeState(aCompleted);
+	    }
+
+	TRestoreTransactionState restoreState(*this, aCurrent, aTimer, aTimer2);
+    CleanupStack::PushL(restoreState.CleanupItem());
+    
+	TRAPD(err,PassResponseToUserAgentL(aResponse));
+	if( err != KErrNone )
+		{
+		if( err == KErrNoMemory || !isErrResponse )
+			{
+			User::Leave(err);
+			}
+		else
+			{
+			iDTimerErrCode = err;
+			}
+		}
+		
+    CleanupStack::Pop(); //cleanupItem  
+
+    if (ack)
+    	{
+    	CleanupStack::Pop(ack);
+		SendAck(ack);
+    	}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::SendAck
+// Can't leave as response's ownership has been passed. Cancel CTransmitter if
+// needed so ACK can be sent. Transaction doesn't own INVITE, so ACK is put to
+// iOutgoingMsg, in place of INVITE.
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::SendAck(CSIPRequest* aAck)
+	{
+	__TEST_INVARIANT;
+
+	if (IsTransmitterSending())
+		{
+		iTransmitter->Cancel();
+		}
+
+	iOutgoingMsg = aAck;
+	iTaOwnsRequest = ETrue;
+
+	TRAPD(err, SendToTransmitterL());
+	if (err != KErrNone)
+		{
+		TRAP_IGNORE(TerminatedL(err))
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::MakeAckLC
+// Create ACK just once. Copy To-header from the response.
+// -----------------------------------------------------------------------------
+//
+CSIPRequest* CInviteClientTransaction::MakeAckLC(CSIPResponse& aResp) const
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_LEAVE(!iTaOwnsRequest, KErrAlreadyExists);	
+
+	CSIPRequest* ack =
+		CSIPRequest::NewLC(SIPStrings::StringF(SipStrConsts::EAck));
+	CopyHeadersFromInviteToAckL(*ack);
+
+	RStringF to = SIPStrings::StringF(SipStrConsts::EToHeader);
+	__SIP_ASSERT_LEAVE(aResp.HasHeader(to), KErrArgument);
+	CSIPMessageUtility::CopyHeadersL(aResp, *ack, to);
+
+	SIPRequestUtility::FillNewMaxForwardsL(*ack);
+	CSIPMessageUtility::CopyAuthorizationHeadersL(iOutgoingMsg, *ack);
+	SIPRequestUtility::FillSupportedSecAgreeL(*ack);
+
+    __TEST_INVARIANT;
+    return ack;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::CopyHeadersFromInviteToAckL
+// Copy INVITE's Via header to ACK. Both have the same CSeq sequence number.
+// -----------------------------------------------------------------------------
+//
+void
+CInviteClientTransaction::CopyHeadersFromInviteToAckL(CSIPRequest& aAck) const
+	{
+	__TEST_INVARIANT;
+    __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound);
+
+    RStringF from   = SIPStrings::StringF(SipStrConsts::EFromHeader);
+    RStringF callId = SIPStrings::StringF(SipStrConsts::ECallIDHeader);
+    RStringF via    = SIPStrings::StringF(SipStrConsts::EViaHeader);
+    RStringF cseq   = SIPStrings::StringF(SipStrConsts::ECSeqHeader);
+
+    __SIP_ASSERT_LEAVE(iOutgoingMsg->HasHeader(from) &&
+    				   iOutgoingMsg->HasHeader(callId) &&
+    				   iOutgoingMsg->HasHeader(via) &&
+    				   iOutgoingMsg->HasHeader(cseq), KErrSIPMalformedMessage);
+
+	const CURIContainer* origReqUri =
+        static_cast<CSIPRequest*>(iOutgoingMsg)->RequestURI();
+    __SIP_ASSERT_LEAVE(origReqUri != NULL, KErrSIPMalformedMessage);
+
+	CURIContainer* reqUri = CURIContainer::NewLC(*origReqUri);
+	aAck.SetRequestURIL(reqUri);
+	CleanupStack::Pop(reqUri);
+
+	CSIPMessageUtility::CopyHeadersL(*iOutgoingMsg, aAck, from);
+	CSIPMessageUtility::CopyHeadersL(*iOutgoingMsg, aAck, callId);
+	CSIPMessageUtility::CopyHeadersL(*iOutgoingMsg, aAck, via);
+
+	TSglQueIter<CSIPHeaderBase> iter = iOutgoingMsg->Headers(cseq);
+	CSIPMessageUtility::FillCSeqL(aAck,
+								  static_cast<CSIPCSeqHeader&>(*iter).Seq(),
+								  SIPStrings::StringF(SipStrConsts::EAck));
+	CSIPMessageUtility::CopyHeadersL(*iOutgoingMsg,
+							 aAck,
+							 SIPStrings::StringF(SipStrConsts::ERouteHeader));
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StartTimerAL
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StartTimerAL()
+	{
+	__TEST_INVARIANT;
+    __SIP_ASSERT_LEAVE(!iTimerA, KErrAlreadyExists);
+
+	if (iTimerADuration == 0)
+		{
+		iTimerADuration = iTimerValues.T1();
+		}
+	else
+		{
+		iTimerADuration = iTimerADuration << 1;
+		}
+
+	iTimerA = CTimerRetransmit::NewL(iTimers, this, iTimerADuration);
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StartTimerBUnlessExistsL
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StartTimerBUnlessExistsL()
+	{
+	__TEST_INVARIANT;
+
+	if (!iTimerB)
+		{
+		iTimerB = CTimerTerminateTa::NewL(iTimers,
+										  this,
+										  iTimerValues.Duration64xT1(),
+										  KErrTimedOut);
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StartTimerDUnlessExistsL
+// Duration is 0s for reliable and 65*T1 for unreliable transports.
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StartTimerDUnlessExistsL()
+	{
+	__TEST_INVARIANT;
+
+    if (!iTimerD)
+    	{
+		TUint32 duration = 0;
+		if (IsUnreliableTransportUsed())
+			{
+			duration = iTimerValues.Duration64xT1() + iTimerValues.T1();
+			}
+	    iTimerD = CTimerTerminateTa::NewL(iTimers, this, duration,iDTimerErrCode);
+    	}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StartTimerProceedingL
+// -----------------------------------------------------------------------------
+//
+CTransactionTimer* CInviteClientTransaction::StartTimerProceedingL()
+	{		
+	__TEST_INVARIANT;
+    __SIP_ASSERT_LEAVE(!iTimerProceeding, KErrAlreadyExists);
+
+	iTimerProceeding =
+        CTimerTerminateTa::NewL(iTimers,
+								this,
+								CTimerTerminateTa::KProceedingTimerDuration,
+								KErrTimedOut);
+	__TEST_INVARIANT;
+	return iTimerProceeding;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StartTimerNATL
+// If 1xx comes before SendCompleteL, timer exists when handling SendCompleteL.
+// -----------------------------------------------------------------------------
+//
+CTransactionTimer*  CInviteClientTransaction::StartTimerNATL()
+	{
+	__TEST_INVARIANT;
+
+	if (!iTimerNAT && iRetransmitInvite && IsUnreliableTransportUsed())
+		{
+		iTimerNAT = CTimerRetransmit::NewL(iTimers,
+									   this,
+									   CTimerRetransmit::KNATBindingInterval);
+		}
+
+	__TEST_INVARIANT;
+	return iTimerNAT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StopTimerA
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StopTimerA()
+	{
+	__TEST_INVARIANT;
+
+	delete iTimerA;
+	iTimerA = NULL;
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StopTimerB
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StopTimerB()
+	{
+	__TEST_INVARIANT;
+
+	delete iTimerB;
+	iTimerB = NULL;
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StopTimerD
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StopTimerD()
+	{
+	__TEST_INVARIANT;
+
+	delete iTimerD;
+	iTimerD = NULL;
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StopTimerProceeding
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StopTimerProceeding()
+	{
+	__TEST_INVARIANT;
+
+	delete iTimerProceeding;
+	iTimerProceeding = NULL;
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::StopTimerNAT
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::StopTimerNAT()
+	{
+	__TEST_INVARIANT;
+
+	delete iTimerNAT;
+	iTimerNAT = NULL;
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::DeleteTimer
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::DeleteTimer(const CTransactionTimer& aTimer)
+	{
+	__TEST_INVARIANT;    
+
+	if (&aTimer == iTimerA)
+		{
+		StopTimerA();
+		}
+
+	if (&aTimer == iTimerB)
+		{
+		StopTimerB();		
+		}
+
+	if (&aTimer == iTimerD)
+		{
+		StopTimerD();		
+		}
+
+	if (&aTimer == iTimerProceeding)
+		{
+		StopTimerProceeding();
+		}
+
+	if (&aTimer == iTimerNAT)
+		{		
+		StopTimerNAT();
+		}
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::CancelAllTimers
+// -----------------------------------------------------------------------------
+//
+void CInviteClientTransaction::CancelAllTimers()
+	{
+	__TEST_INVARIANT;
+
+	StopTimerA();
+	StopTimerB();
+	StopTimerD();
+	StopTimerProceeding();
+	StopTimerNAT();
+
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::Ptr
+// -----------------------------------------------------------------------------
+//
+CInviteClientTransaction&
+CInviteClientTransaction::Ptr(CTransaction& aTransaction)
+	{
+	return static_cast<CInviteClientTransaction&>(aTransaction);
+	}
+
+// -----------------------------------------------------------------------------
+// CInviteClientTransaction::__DbgTestInvariant
+// iTaOwnsRequest can be ETrue only if iOutgoingMsg is ACK.
+// -----------------------------------------------------------------------------
+//
+
+void CInviteClientTransaction::__DbgTestInvariant() const
+	{
+	if (iOutgoingMsg &&
+		iTaOwnsRequest &&
+		!CSIPMessageUtility::IsAck(*iOutgoingMsg) &&
+		(iRetransmitInvite && !iTimerNAT ||
+		 !iRetransmitInvite && iTimerNAT))
+		{
+		User::Invariant();
+		}
+	}