realtimenetprots/sipfw/SIP/TransactionUser/src/InviteUAC.cpp
author Petteri Saari <petteri.saari@digia.com>
Thu, 25 Nov 2010 13:59:42 +0200
branchMSRP_FrameWork
changeset 58 cdb720e67852
parent 0 307788aac0a8
permissions -rw-r--r--
This release addresses the following issues: 1. The crash bug fix when receiving file 2. Now the sending is based on MSRP messages, there is no longer file receiving or sending. Client sends data as MSRP was designed. 3. Soma MSRP stack was created so that the client told the correct session-id, Symbian stack generated it by itself. This is not allowed, it was changed so that clients tell the session-id (same as used in SIP INVITE). 4. Unnecessary division of data to chunks removed when there is no need to interrupt sending. The message is sent in as few chunks as possible. 5. Stack can now receive files and chunks with ?unlimited? size. Old stack wrote the incoming data to memory and did not utilize disk space until the end of chunk was reached (large chunks from another client crashed it). 6. Now when writing the incoming data to file, it will take into account the byte-range header values. So, this complies with the RFC4975 requirements that stack must be able to handle chunks that come in any sequence. 7. Some buffering changes to outgoing/incoming data. 8. The outgoing data is now checked that it does not contain the created transaction-id before sending the data. 9. MSRP success reports are now implemented and tested against servers. 10. Progress report system fixed so progress is now visible on client (all the way to 100%). 11. Message Cancel receiving / Cancel sending now corrected and made to work as rfc4975 requires. (termination from sender and error code from receiver when cancelling). 12. Bug correction related to messages received not belonging to any session, old stack implementation did send error response, but after response was written it did give the buffer to client anyway. Now corrected.

// 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();
		}
	}