--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/TransactionUser/src/InviteUAC.cpp Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,695 @@
+// 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();
+ }
+ }