realtimenetprots/sipfw/SIP/TransactionUser/src/InviteUAC.cpp
author Stefan Karlsson <stefan.karlsson@nokia.com>
Sat, 10 Apr 2010 13:41:16 +0100
branchCompilerCompatibility
changeset 13 4f4a686bcb0a
parent 0 307788aac0a8
permissions -rw-r--r--
Got rid of some trivial warnings (nested comments and tokens after #endif).

// 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          : InviteUAC.cpp
// Part of       : TransactionUser
// Version       : SIP/6.0
//



#include "siperr.h"
#include "sipfromheader.h"
#include "sipviaheader.h"
#include "siprequest.h"
#include "sipresponse.h"
#include "sipstrings.h"
#include "sipstrconsts.h"
#include "MSipRegistrations.h"
#include "TransactionMgr.h"
#include "ClientTransaction.h"
#include "Transmitter.h"
#include "DeleteMgr.h"
#include "SipAssert.h"

#include "InviteUAC.h"
#include "InviteUACStates.h"
#include "CTransactionStore.h"
#include "SIPMessageUtility.h"
#include "SIPRequestUtility.h"
#include "TimerValues.h"
#include "UserAgentTimer.h"
#include "UserAgentCreateParams.h"
#include "RouteSet.h"
#include "ResolvingResults.h"


// -----------------------------------------------------------------------------
// CInviteUAC::NewL
// -----------------------------------------------------------------------------
//
CInviteUAC* CInviteUAC::NewL(CUserAgentCreateParams& aParams,							 
                             MSipConnectionMgr& aConnectionMgr,
                             MSipUriResolver& aResolver,							 
							 CSIPSec& aSIPSec,
							 TUint32 aCSeqNumber,
							 TBool aIsPrivateAddress,
							 CUserAgentState* aAckSenderState)
	{
	CInviteUAC* self = new (ELeave) CInviteUAC(aParams,
											   aConnectionMgr,
                                               aResolver,											   
											   aSIPSec,
											   aCSeqNumber,
											   aIsPrivateAddress,
											   aAckSenderState);
	CleanupStack::PushL(self);
	self->CUserAgent::ConstructL(aConnectionMgr);
	self->CUserAgentClient::ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::CInviteUAC
// -----------------------------------------------------------------------------
//
CInviteUAC::CInviteUAC(CUserAgentCreateParams& aParams,					   
                       MSipConnectionMgr& aConnectionMgr,
                       MSipUriResolver& aResolver,					   
					   CSIPSec& aSIPSec,
					   TUint32 aCSeqNumber,
					   TBool aIsPrivateAddress,
					   CUserAgentState* aAckSenderState) :
	CUserAgentClient(aParams, aResolver, aSIPSec, aCSeqNumber),
	iConnectionMgr(aConnectionMgr),	
	iIsPrivateAddress(aIsPrivateAddress),
	iAckSenderState(aAckSenderState)
#ifdef CPPUNIT_TEST
    , iAckSenders(1)
#endif
	{
	}

// -----------------------------------------------------------------------------
// CInviteUAC::~CInviteUAC
// -----------------------------------------------------------------------------
//
CInviteUAC::~CInviteUAC()
	{
	CancelAllTimers();
	iAckSenders.ResetAndDestroy();
	delete iDeleteThisTransaction;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::ReceiveResponseL
// Application sends ACK (uses ITC) to 2xx, so stop transaction and enter next
// state after PassRespToTransactionOwnerL, as ACK isn't sent inside it.
// -----------------------------------------------------------------------------
//
void CInviteUAC::ReceiveResponseL(CSIPResponse* aResp,
						  		  const CUserAgentState& aResolve,
						  		  const CUserAgentState& aWaitResponse,
								  const CUserAgentState& aWaitAckFromApp,
								  const CUserAgentState& aWaitTransactionToEnd)
	{
	__TEST_INVARIANT;
	__SIP_ASSERT_LEAVE(aResp, KErrArgument);
	__SIP_ASSERT_LEAVE(!iTimerWait2xxRetransmissions, KErrAlreadyExists);

	if (!ShouldUaTryAgainL(aResp, aResolve, aWaitResponse))
		{
		CSIPResponse::TType type = aResp->Type();
		if (type == CSIPResponse::E2XX)
			{
			// UAC treats INVITE transaction completed 64*T1 after the first
			// 2xx. Expire with KErrNone as UAC ends successfully.
			iTimerWait2xxRetransmissions = CTimerStopUA::NewL(iTimers,
											   this,
											   iTimerValues.Duration64xT1(),
											   KErrNone);
			}
		PassRespToTransactionOwnerL(aResp,
									// If timer, set UA and timer pointers
									iTimerWait2xxRetransmissions ? this : NULL,
									iTimerWait2xxRetransmissions);
		if (type == CSIPResponse::E2XX)
			{
			StopTransaction();
			ChangeState(aWaitAckFromApp);
			}
	    else if (type == CSIPResponse::E1XX)
			{
			// Pass 1xx to upper layer
			}
	    else
	        {
	        // Transaction sends ACK, UAC waits it to end
			ChangeState(aWaitTransactionToEnd);
	        }
		}

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::PrepareTxForNewRequestL
// -----------------------------------------------------------------------------
//
void CInviteUAC::PrepareTxForNewRequestL(TTransactionId& aNewTransactionId)

	{
	__TEST_INVARIANT;

	CTransmitter* transmitter = CTransmitter::NewL(iConnectionMgr);
    static_cast<CClientTransaction*>(iTransaction)->
        RunIndependently(aNewTransactionId, &iDeleteMgr, EFalse);
    iTransmitter = transmitter;

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::CreateTransactionL
// -----------------------------------------------------------------------------
//
void CInviteUAC::CreateTransactionL()
	{
	__TEST_INVARIANT;
    __SIP_ASSERT_LEAVE(!iTransaction, KErrAlreadyExists);

	iTransaction = iTransactionMgr.CreateTransactionL(
		CTransactionBase::KClientInviteTransaction,
		*this,
		*iTransmitter,
		iTimerValues,
		iIsPrivateAddress && !iRegistrations.IsOutboundProxy(NextHopL()));
	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::ClearTransactionOwner
// -----------------------------------------------------------------------------
//
void CInviteUAC::ClearTransactionOwner()
	{
	__TEST_INVARIANT;	
	
	for (TInt i = 0; i < iAckSenders.Count(); i++)
	    {
	    iAckSenders[i]->ClearTransactionOwner();
	    }
    CUserAgent::ClearTransactionOwner();

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::DeleteTimer
// -----------------------------------------------------------------------------
//
void CInviteUAC::DeleteTimer(const CUserAgentTimer& aTimer)
	{
	__TEST_INVARIANT;

	if (&aTimer == iTimerWait2xxRetransmissions)
		{
		StopTimerUaTimeout();
		}
	if (&aTimer == iSIPSecTimer)
		{
		StopTimerSIPSec();
		}

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::IsInviteUAC
// -----------------------------------------------------------------------------
//
TBool CInviteUAC::IsInviteUAC() const
	{
	__TEST_INVARIANT;
	return ETrue;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::IsSubInviteUAC
// -----------------------------------------------------------------------------
//
TBool CInviteUAC::IsSubInviteUAC() const
	{
	__TEST_INVARIANT;
	return iAckSenderState == NULL;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::IsCanceled
// -----------------------------------------------------------------------------
//
TBool CInviteUAC::IsCanceled() const
	{
	__TEST_INVARIANT;
	return iCanceled;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::StartSIPSecTimerL
// -----------------------------------------------------------------------------
//
void CInviteUAC::StartSIPSecTimerL()
	{
	__TEST_INVARIANT;
	__SIP_ASSERT_LEAVE(!iSIPSecTimer, KErrAlreadyExists);

	iSIPSecTimer = CTimerAsyncSIPSec::NewL(iTimers, this);

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::SendAckL
// -----------------------------------------------------------------------------
//
void CInviteUAC::SendAckL(CSIPRequest* aAck,
						  MTransactionOwner& aObserver,
						  const TSIPTransportParams& aParams,
						  TRegistrationId aRegisterId,
						  const CURIContainer& aRemoteTarget,
						  TBool aDeleteRequest,
						  RStringF aBranch)
	{
	__TEST_INVARIANT;
    __SIP_ASSERT_LEAVE(aAck, KErrArgument);

	State().SendAckL(*this,
					 aAck,
					 aObserver,
					 aParams,
					 aRegisterId,
					 aRemoteTarget,
					 aDeleteRequest,
					 aBranch);	
	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::CancelInvite
// -----------------------------------------------------------------------------
//
void CInviteUAC::CancelInvite()
	{
	__TEST_INVARIANT;

	iCanceled = ETrue;
	
	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::CopyRouteHeadersToCancelL
// -----------------------------------------------------------------------------
//
void CInviteUAC::CopyRouteHeadersToCancelL(CSIPRequest& aCancel)
	{
	__TEST_INVARIANT;
    __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound);

	CSIPMessageUtility::CopyHeadersL(*iOutgoingMsg,
						 aCancel,
						 SIPStrings::StringF(SipStrConsts::ERouteHeader));
	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::HandleIcmpErrorL
// Cancel send. If 2 UAs use same address, one gets ICMP error KErrSIPICMPFailure and its send ends
// but the other can be active. Unless UA stops, pass ICMP error to "sub UACs".
// -----------------------------------------------------------------------------
//
void CInviteUAC::HandleIcmpErrorL(const TInetAddr& aAddress,
								  const CUserAgentState& aResolveAckAddress,
								  const CUserAgentState& aWaitResponse)
	{
	__TEST_INVARIANT;

	if (CSIPMessageUtility::CompareTInetAddr(iRemoteAddr,
											 iTransportProtocol,
											 aAddress))
		{
		iTransmitter->Cancel();
		TInt error = KErrSIPICMPFailure;
		if (!TryNextAddressL(error, aResolveAckAddress, aWaitResponse))
			{
            Stop(error);
            return;
			}
		}

	for (TInt i = 0; i < iAckSenders.Count(); ++i)
		{
        // Use any error code. "sub UAC" stops with CSIP::ETransportFailure.
		iAckSenders[i]->IcmpErrorL(aAddress,
								   CSipConnectionMgr::EHostUnreachable);
		}

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::CheckAckL
// Application must fill To-header, as many 2xx (each with a unique To-tag) can
// arrive and UAC won't know which tag to put in To-header.
// -----------------------------------------------------------------------------
//
void CInviteUAC::CheckAckL(CSIPRequest& aAck) const
	{
	__TEST_INVARIANT;

    if (!aAck.HasHeader(SIPStrings::StringF(SipStrConsts::EToHeader)) ||
        aAck.HasHeader(SIPStrings::StringF(SipStrConsts::EViaHeader)))
        {
        User::Leave(KErrSIPMalformedMessage);
        }
	}

// -----------------------------------------------------------------------------
// CInviteUAC::FillAckL
// -----------------------------------------------------------------------------
//
void CInviteUAC::FillAckL(CSIPRequest& aAck, RStringF aBranch)
	{
	__TEST_INVARIANT;
	__SIP_ASSERT_LEAVE(iRemoteTarget, KErrNotFound);

	SIPRequestUtility::FillRouteAndRequestUriL(aAck,
											   *iRouteSet,
											   *iRemoteTarget);
    // Copy From-header before Contact-headers are handled
	iTransactionStore.CopyHeadersToRequestL(TransactionId(),
											aAck,
											EFalse, // Request-URI already set
											EFalse);// Don't copy Via
	CheckContactHeadersL(aAck, aAck.From());

	if (!aAck.HasHeader(SIPStrings::StringF(SipStrConsts::EMaxForwardsHeader)))
		{
		SIPRequestUtility::FillNewMaxForwardsL(aAck);
		}

    FillNewViaL(aAck, aBranch);
    // "sub UAC" has no iOutgoingMsg, but the authorization headers have already
    // been copied from the first ACK.
	CSIPMessageUtility::CopyAuthorizationHeadersL(iOutgoingMsg, aAck);
	SIPRequestUtility::FillSupportedSecAgreeL(aAck);

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::AckAddressResolvedL
// Remote address must exist.
// -----------------------------------------------------------------------------
//
void CInviteUAC::AckAddressResolvedL()
	{
	__TEST_INVARIANT;	
	__SIP_ASSERT_LEAVE(SelectNextRemoteAddressL(), KErrNotFound);

	if (FillSecurityParamsL())
		{
		SendRequestToNetworkL();
		}

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::SendFirstAckL
// Clear INVITE's route set and resolving results before resolving ACK address.
// -----------------------------------------------------------------------------
//
void CInviteUAC::SendFirstAckL(CSIPRequest* aAck,
							   MTransactionOwner& aObserver,
							   const TSIPTransportParams& aParams,
							   TRegistrationId aRegisterId,
							   const CURIContainer& aRemoteTarget,
							   TBool aDeleteRequest,
							   RStringF aBranch)
	{
	__TEST_INVARIANT;
    __SIP_ASSERT_LEAVE(aAck, KErrArgument);
    __SIP_ASSERT_LEAVE(!iObserverForFirstAck, KErrAlreadyExists);
    // Main-UAC must always use a new branch
    if (iAckSenderState && aBranch != SIPStrings::StringF(SipStrConsts::EEmpty))
    	{
    	User::Leave(KErrArgument);
    	}

	iObserver = &aObserver;
	iObserverForFirstAck = &aObserver;
	iRegisterId = aRegisterId;
	iTransportParams = aParams;	

    CheckAckL(*aAck);
	StoreRemoteTargetL(aRemoteTarget);

	delete iRouteSet;
    iRouteSet = NULL;
	iRouteSet = CRouteSet::NewL(*aAck, iRegistrations, iRegisterId);

	FillAckL(*aAck, aBranch);
	StoreRequestUriL(*aAck);

	iResolvingResults->ClearAll();
	ResolveNextHopL(ETrue);

	StoreOutgoingMsg(aAck);
	SetRequestOwnership(aDeleteRequest);

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::SendAdditionalAckL
// Get branch value before updating observer. Don't update iObserverForFirstAck.
// -----------------------------------------------------------------------------
//
void CInviteUAC::SendAdditionalAckL(CSIPRequest* aAck,
									MTransactionOwner& aObserver,
								    const TSIPTransportParams& aParams,
									TRegistrationId aRegisterId,
									const CURIContainer& aRemoteTarget,
									TBool aDeleteRequest)
	{
	__TEST_INVARIANT;
    __SIP_ASSERT_LEAVE(aAck, KErrArgument);

	iObserver = &aObserver;
	iRegisterId = aRegisterId;

	CUserAgentCreateParams* params =
        CUserAgentCreateParams::NewLC(iTransactionMgr,
                                      iTimers,
								      iSIPMsgUtility,
								      iTimerValues,
								      iRegistrations,
                                      iRegistrationContact,
                                      iSigComp,
                                      iTransactionStore,
                                      iDeleteMgr,
								      aDeleteRequest,
								      aParams);
	params->iTransactionId = TransactionId();	
	params->iObserver = iObserver;
	params->iInitialUaState = iAckSenderState;

	CInviteUAC* subUac =
		CInviteUAC::NewL(*params,
					     iConnectionMgr,
					     iResolver,
					     iSIPSec,
					     0, // CSeq value not used for ACK
					     iIsPrivateAddress, // Not used for ACK
					     NULL); // State is NULL for "sub UAC"
	CleanupStack::PopAndDestroy(params);
	CleanupStack::PushL(subUac);
	iAckSenders.AppendL(subUac);
    CleanupStack::Pop(subUac);

	CSIPMessageUtility::CopyAuthorizationHeadersL(iOutgoingMsg, *aAck);
	subUac->SendAckL(aAck,
					 *iObserver,
					 aParams,
					 iRegisterId,
					 aRemoteTarget,
					 aDeleteRequest,
					 SelectBranchToUse(aObserver));
	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::HandleAdditional2xxL
// SIPSec must handle 2xx synchronously. PassRespToTransactionOwnerL allows only
// one final response, so use PassMsgToTransactionOwnerL. Drop other responses.
// -----------------------------------------------------------------------------
//
void CInviteUAC::HandleAdditional2xxL(CSIPResponse* aResp)
	{
	__TEST_INVARIANT;
    __SIP_ASSERT_LEAVE(aResp, KErrArgument);

    if (aResp->Type() == CSIPResponse::E2XX)
		{
        __SIP_ASSERT_LEAVE(!PassResponseToSIPSecL(*aResp), KErrGeneral);
		PassMsgToTransactionOwnerL(aResp);
		}
	else
		{
		delete aResp;
		}
	}

// -----------------------------------------------------------------------------
// CInviteUAC::Ptr
// -----------------------------------------------------------------------------
//
CInviteUAC& CInviteUAC::Ptr(CUserAgent& aUserAgent)
	{
	return static_cast<CInviteUAC&>(aUserAgent);
	}

// -----------------------------------------------------------------------------
// CInviteUAC::StopTransaction
// Even if AddDeleteRequest fails, transaction is detached and won't receive
// messages. Transaction doesn't know its id, so write log here.
// -----------------------------------------------------------------------------
//
void CInviteUAC::StopTransaction()
	{
	__TEST_INVARIANT;
	__SIP_ASSERT_RETURN(iTransaction, KErrNotFound);
	__SIP_ASSERT_RETURN(!iDeleteThisTransaction, KErrAlreadyExists);

	// Prevent transaction from calling TransactionEndsL
	iTransaction->DetachFromUserAgent();
	iTransaction->Terminated();
	__SIP_INT_LOG1("TU transaction state=Terminated, taID", TransactionId() )

	if (iDeleteMgr.AddDeleteRequest(iTransaction) != KErrNone)
		{
		iDeleteThisTransaction = iTransaction;
		}
	iTransaction = NULL;
	iTransactionStore.ClearTransaction(TransactionId());

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::StopTimerUaTimeout
// -----------------------------------------------------------------------------
//
void CInviteUAC::StopTimerUaTimeout()
	{
	__TEST_INVARIANT;

	delete iTimerWait2xxRetransmissions;
	iTimerWait2xxRetransmissions = NULL;

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::StopTimerSIPSec
// -----------------------------------------------------------------------------
//
void CInviteUAC::StopTimerSIPSec()
	{
	__TEST_INVARIANT;

	delete iSIPSecTimer;
	iSIPSecTimer = NULL;

	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::CancelAllTimers
// -----------------------------------------------------------------------------
//
void CInviteUAC::CancelAllTimers()
	{
	__TEST_INVARIANT;

	StopTimerUaTimeout();
	StopTimerSIPSec();
	
	__TEST_INVARIANT;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::SelectBranchToUse
// -----------------------------------------------------------------------------
//
RStringF CInviteUAC::SelectBranchToUse(MTransactionOwner& aObserver) const
	{
	__TEST_INVARIANT;

	const RStringF KEmpty = SIPStrings::StringF(SipStrConsts::EEmpty);
	RStringF branch = UsedBranch(aObserver);

	for (TInt i = 0; branch == KEmpty && i < iAckSenders.Count(); ++i)
		{
		branch = iAckSenders[i]->UsedBranch(aObserver);
		}
	return branch;
	}

// -----------------------------------------------------------------------------
// CInviteUAC::UsedBranch
// -----------------------------------------------------------------------------
//
RStringF CInviteUAC::UsedBranch(MTransactionOwner& aObserver) const
	{
	__TEST_INVARIANT;

	if ((&aObserver == iObserverForFirstAck) && iOutgoingMsg)
		{
		const RStringF KBranch = SIPStrings::StringF(SipStrConsts::EBranch);
		CSIPViaHeader* via = CSIPMessageUtility::TopVia(*iOutgoingMsg);
    	if (via && via->HasParam(KBranch))
    		{
    		return via->ParamValue(KBranch);
    		}
		}
	return SIPStrings::StringF(SipStrConsts::EEmpty);
	}
	
// -----------------------------------------------------------------------------
// CInviteUAC::SetSipSecError
// -----------------------------------------------------------------------------
//
void CInviteUAC::SetSipSecError(TInt aErr)
    {
    iSipSecError = aErr;
    }

// -----------------------------------------------------------------------------
// CInviteUAC::__DbgTestInvariant
// -----------------------------------------------------------------------------
//

void CInviteUAC::__DbgTestInvariant() const
	{
	// A "sub UAC" can't have "sub UACs" or timer
    if (!iAckSenderState &&
        (iAckSenders.Count() > 0 ||
         iTimerWait2xxRetransmissions ||
         iSIPSecTimer))
		{
		User::Invariant();
		}
	}