diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/TransactionUser/src/UserAgentClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/SIP/TransactionUser/src/UserAgentClient.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,1283 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).627 + +// 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 : UserAgentClient.cpp +// Part of : TransactionUser +// Version : SIP/6.0 +// + + + +#include "siperr.h" +#include "SipAssert.h" +#include "MSipRegistrations.h" +#include "sipcseqheader.h" +#include "sipuri.h" +#include "uricontainer.h" +#include "siphostport.h" +#include "sipaddress.h" +#include "sipcallidheader.h" +#include "sipviaheader.h" +#include "sipfromheader.h" +#include "siprouteheader.h" +#include "sipstrings.h" +#include "sipstrconsts.h" +#include "sipsec.h" +#include "siprequest.h" +#include "sipresponse.h" +#include "Transmitter.h" + +#include "UserAgentClient.h" +#include "UserAgentState.h" +#include "CTransactionStore.h" +#include "SIPMessageUtility.h" +#include "SIPRequestUtility.h" +#include "MTransactionUser.h" +#include "MTransactionOwner.h" +#include "RouteSet.h" +#include "ResolvingResults.h" +#include "StopUserAgent.h" +#include "RestoreUaState.h" +#include "MSIPSecUser.h" + +// ----------------------------------------------------------------------------- +// CUserAgentClient::CUserAgentClient +// ----------------------------------------------------------------------------- +// +CUserAgentClient::CUserAgentClient(CUserAgentCreateParams& aParams, + MSipUriResolver& aResolver, + CSIPSec& aSIPSec, + TUint32 aCSeqNumber) : + CUserAgent(aParams), + iSIPSec(aSIPSec), + iCSeqNumber(aCSeqNumber), + iResolver(aResolver), + iSipSecError(KErrNone), + iFinalRespPassed(EFalse), + iOutboundProxyHasBeenTried(EFalse), + iLastError(KErrNone), + iIgnoreSIPSecCallback(EFalse) + { + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::ConstructL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::ConstructL() + { + iResolvingResults = CResolvingResults::NewL(); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::~CUserAgentClient +// ----------------------------------------------------------------------------- +// +CUserAgentClient::~CUserAgentClient() + { + iResolver.CancelGetByUri(this); + CancelSIPSecRequest(); + delete iResolvingResults; + delete iRemoteTarget; + delete iRouteSet; + delete iRequestUri; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::IsUAS +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::IsUAS() const + { + __TEST_INVARIANT; + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::RegistrationId +// ----------------------------------------------------------------------------- +// +TRegistrationId CUserAgentClient::RegistrationId() const + { + __TEST_INVARIANT; + return iRegisterId; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::CompletedL +// Resolving succeeded so clear the stored error. +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::CompletedL() + { + __TEST_INVARIANT; + + if (!HasStopped()) + { + iLastError = KErrNone; + delete iIncomingMsg; + iIncomingMsg = NULL; + State().AddressResolvedL(*this); + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::ErrorOccured +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::ErrorOccured(TInt aError) + { + __TEST_INVARIANT; + + if (!HasStopped()) + { + if (aError == KErrSIPResolvingFailure) + { + // URI fully resolved. Old results not needed. + iResolvingResults->ClearAll(); + State().ResolvingFailed(*this); + } + else + { + // Leave came in MSIPServerResolverObserver::CompletedL + Stop(aError); + } + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SIPSecCacheUpdated +// Don't use __TEST_INVARIANT as destructor may lead here. +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::SIPSecCacheUpdated(TBool aSuccess) + { + if (!iIgnoreSIPSecCallback) + { + SIPSecReady(aSuccess); + } + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SIPSecTimerExpiredL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::SIPSecTimerExpiredL() + { + __TEST_INVARIANT; + + TInt err = SIPSecReady(ETrue); + if (err != KErrNone) + { + User::Leave(err); + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SIPSecReady +// TRAP may delete UA. Check if UA exists before stopping. Don't use +// __TEST_INVARIANT after Stop. +// ----------------------------------------------------------------------------- +// +TInt CUserAgentClient::SIPSecReady(TBool aSuccess) + { + __TEST_INVARIANT; + + TTransactionId transactionId = TransactionId(); + CTransactionStore& store = iTransactionStore; + + TRAPD(err, State().SIPSecCacheUpdatedL(*this, aSuccess)); + if (err != KErrNone && store.SearchById(transactionId)) + { + Stop(err); + } + + return err; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::HandleSendRequestL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::HandleSendRequestL(CSIPRequest* aReq, + TRegistrationId aRegisterId, + const CURIContainer& aRemoteTarget, + const CUserAgentState& aResolve) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(aReq, KErrArgument); + __SIP_ASSERT_LEAVE(!iRouteSet && !iRemoteTarget, KErrAlreadyExists); + + iRegisterId = aRegisterId; + StoreRemoteTargetL(aRemoteTarget); + iRouteSet = CRouteSet::NewL(*aReq, iRegistrations, iRegisterId); + + SIPRequestUtility::CheckOutgoingRequestL(*aReq); + FillRequestL(*aReq); + StoreRequestUriL(*aReq); + + TBool isRegMsg = (SIPStrings::StringF(SipStrConsts::ERegister) == aReq->Method()); + ResolveNextHopL(ETrue,!isRegMsg); + + UpdateInfoToStoreL(aReq); + StoreOutgoingMsg(aReq); + ChangeState(aResolve); + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::FillRequestL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::FillRequestL(CSIPRequest& aReq) const + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iRouteSet && iRemoteTarget, KErrNotFound); + + CSIPMessageUtility::FillCSeqL(aReq, iCSeqNumber, aReq.Method()); + + if (!aReq.HasHeader(SIPStrings::StringF(SipStrConsts::ECallIDHeader))) + { + FillNewCallIdL(aReq); + } + + if (!aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EMaxForwardsHeader))) + { + SIPRequestUtility::FillNewMaxForwardsL(aReq); + } + + CheckContactHeadersL(aReq, aReq.From()); + SIPRequestUtility::FillRouteAndRequestUriL(aReq, + *iRouteSet, + *iRemoteTarget); + FillNewViaL(aReq, SIPStrings::StringF(SipStrConsts::EEmpty)); + + CSIPFromHeader* from = aReq.From(); + __SIP_ASSERT_LEAVE(from != NULL, KErrArgument); + if (!from->HasParam(SIPStrings::StringF(SipStrConsts::ETag))) + { + AddTagL(*from); + } + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::UpdateViaAndCSeqL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::UpdateViaAndCSeqL() const + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound); + + CSIPRequest* req = static_cast(iOutgoingMsg); + FillNewViaL(*req, SIPStrings::StringF(SipStrConsts::EEmpty)); + + CSIPCSeqHeader* cseqHeader = req->CSeq(); + __SIP_ASSERT_LEAVE(cseqHeader != NULL, KErrSIPMalformedMessage); + TUint cseq = cseqHeader->Seq(); + + if (iObserver) + { + User::LeaveIfError(iObserver->NextCSeq(cseq)); + } + else + { + ++cseq; + } + cseqHeader->SetSeq(cseq); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::FillNewCallIdL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::FillNewCallIdL(CSIPRequest& aReq) const + { + __TEST_INVARIANT; + + TBuf8 callID; + AddRandomStringL(callID, MTransactionUser::KCallIDLength, ETrue); + CSIPCallIDHeader* callIdHeader = CSIPCallIDHeader::DecodeL(callID); + CleanupStack::PushL(callIdHeader); + aReq.AddHeaderL(callIdHeader); + CleanupStack::Pop(callIdHeader); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SetBranchL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::SetBranchL(CSIPViaHeader& aVia, RStringF aBranch) const + { + __TEST_INVARIANT; + + if (aBranch == SIPStrings::StringF(SipStrConsts::EEmpty)) + { + const TInt KBranchLength = 30; + __ASSERT_DEBUG( + KBranchLength > CSIPMessageUtility::BranchMagicCookie().Length(), + User::Panic(_L("UAC:SetBranchL"), KErrOverflow)); + TBuf8 branchBuf; + branchBuf.Append(CSIPMessageUtility::BranchMagicCookie()); + AddRandomStringL(branchBuf, KBranchLength - branchBuf.Length(), EFalse); + + RStringF branch = SIPStrings::Pool().OpenFStringL(branchBuf); + CleanupClosePushL(branch); + aVia.SetParamL(SIPStrings::StringF(SipStrConsts::EBranch), branch); + CleanupStack::PopAndDestroy(); // branch + } + else + { + aVia.SetParamL(SIPStrings::StringF(SipStrConsts::EBranch), aBranch); + } + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::FillNewViaL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::FillNewViaL(CSIPRequest& aReq, RStringF aBranch) const + { + __TEST_INVARIANT; + + CSIPViaHeader* via = CSIPMessageUtility::TopVia(aReq); + if (via) + { + SetBranchL(*via, aBranch); + via->SetTransportL(iTransportProtocol); + } + else + { + CSIPHostPort* hp = CSIPHostPort::DecodeL( + SIPStrings::StringF(SipStrConsts::ELocalHost).DesC()); + CleanupStack::PushL(hp); + via = CSIPViaHeader::NewL(iTransportProtocol, hp); + CleanupStack::Pop(hp); + CleanupStack::PushL(via); + + SetBranchL(*via, aBranch); + + aReq.AddHeaderL(via); + CleanupStack::Pop(via); + } + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::StoreRequestUriL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::StoreRequestUriL(CSIPRequest &aReq) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(aReq.RequestURI() != NULL, KErrArgument); + + CURIContainer* newUri = CURIContainer::NewL(*aReq.RequestURI()); + delete iRequestUri; + iRequestUri = newUri; + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::UpdateInfoToStoreL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::UpdateInfoToStoreL(CSIPRequest* aReq) const + { + __TEST_INVARIANT; + + iTransactionStore.UpdateL(TransactionId(), iTransaction, aReq); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::ResolveNextHopL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::ResolveNextHopL(TBool aCheckSigComp,TBool aUseResolvedProxy) + { + __TEST_INVARIANT; + + CURIContainer& uri = NextHopL(aUseResolvedProxy); + if (aCheckSigComp) + { + CheckSigCompL(uri); + } + + iResolver.GetByURIL(uri, + iResolvingResults->Addresses(), + TransportParams(), + this); + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::CopyRemoteAddress +// Clear resolving results as CANCEL must use only one ip-address. +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::CopyRemoteAddress(const CUserAgentClient& aSrc) + { + __TEST_INVARIANT; + + iRemoteAddr = aSrc.iRemoteAddr; + iForceUDP = aSrc.iForceUDP; + + iTransportProtocol.Close(); + if (aSrc.iTransaction) + { + iTransportProtocol = aSrc.iTransaction->TransportProtocol().Copy(); + } + else + { + RStringF protocol = aSrc.iTransportProtocol; + iTransportProtocol = protocol.Copy(); + } + + iResolvingResults->ClearAll(); + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::CopyRouteSetAndRemoteTargetL +// ----------------------------------------------------------------------------- +// +void +CUserAgentClient::CopyRouteSetAndRemoteTargetL(const CUserAgentClient& aSrc) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(!iRouteSet && !iRemoteTarget, KErrAlreadyExists); + __SIP_ASSERT_LEAVE(aSrc.iRouteSet && aSrc.iRemoteTarget, KErrNotFound); + + iRouteSet = CRouteSet::NewL(*aSrc.iRouteSet); + iRemoteTarget = CURIContainer::NewL(*aSrc.iRemoteTarget); + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::StoreRemoteTargetL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::StoreRemoteTargetL(const CURIContainer& aRemoteTarget) + { + __TEST_INVARIANT; + + CURIContainer* newRemoteTarget = CURIContainer::NewL(aRemoteTarget); + delete iRemoteTarget; + iRemoteTarget = newRemoteTarget; + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::NextHopL +// ----------------------------------------------------------------------------- +// +CURIContainer& CUserAgentClient::NextHopL(TBool aUseResolvedProxy) const + { + __TEST_INVARIANT; + __ASSERT_ALWAYS(iRouteSet && iRemoteTarget, + User::Panic(_L("UAC:NextHop"), KErrNotFound)); + + if (aUseResolvedProxy && iRegistrations.HasOutboundProxy(iRegisterId)) + { + if(iRegistrations.OutboundProxy(iRegisterId)->SIPAddress().URI() == + iRouteSet->NextHop(*iRemoteTarget)) + { + if(iRegistrations.IsCacheOutboundProxyIPEanbled(iRegisterId)) + { + TRAPD(err,iRegistrations.OutboundProxyIPL(iRegisterId)) + if(KErrNone == err) + { + return iRegistrations.OutboundProxyIPL(iRegisterId).SIPAddress().URI(); + } + } + } + } + return iRouteSet->NextHop(*iRemoteTarget); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SetRequestOwnership +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::SetRequestOwnership(TBool aOwnsRequest) + { + __TEST_INVARIANT; + + iOwnsOutgoingMsg = aOwnsRequest; + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::StoreResponse +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::StoreResponse(CSIPResponse* aResponse) + { + __TEST_INVARIANT; + __SIP_ASSERT_RETURN(!iIncomingMsg, KErrAlreadyExists); + + iIncomingMsg = aResponse; + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SelectNextRemoteAddressL +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::SelectNextRemoteAddressL() + { + __TEST_INVARIANT; + + iSIPSecCounter = 0; // Remote address changes, reset counter + if (!iResolvingResults->GetNext(iRemoteAddr, iTransportProtocol, iForceUDP)) + { + return EFalse; + } + if(iRemoteAddr.IsUnspecified()) + { + return EFalse; + } + + __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound); + CSIPMessageUtility::UpdateViaTransportL(*iOutgoingMsg, iTransportProtocol); + + __TEST_INVARIANT; + return ETrue; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::RemoteAddressResolvedL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::RemoteAddressResolvedL(const CUserAgentState& aNextState) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(SelectNextRemoteAddressL(), KErrNotFound); + + if (FillSecurityParamsL()) + { + CreateTransactionL(); + UpdateInfoToStoreL(NULL /* don't update message headers */); + SendRequestToNetworkL(); + ChangeState(aNextState); + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::HandleResolvingFailure +// ----------------------------------------------------------------------------- +// +void +CUserAgentClient::HandleResolvingFailure(const CUserAgentState& aResolve, + const CUserAgentState& aWaitResponse) + { + __TEST_INVARIANT; + + TBool retry(ETrue); + TRAPD(err, retry = TryNextAddressL(KErrSIPResolvingFailure, + aResolve, + aWaitResponse)); + if (err != KErrNone || !retry) + { + StopWithLastError(); + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::FillSecurityParamsL +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::FillSecurityParamsL() + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iOutgoingMsg && iRemoteTarget, KErrNotFound); + + if (!iObserver) + { + Stop(KErrNone); + return EFalse; + } + + if (UseSIPSec()) + { + CUri8* remoteTarget = iRemoteTarget->CloneAsUri8L(); + CleanupStack::PushL(remoteTarget); + TRAPD(err, iSIPSec.AddSecurityParamsL( + iTransportParams, + static_cast(*iOutgoingMsg), + RegistrationId(), + TransactionId(), + iRemoteAddr, + CSIPMessageUtility::UriDescriptor(NextHopL()), + *remoteTarget, + ProxyL(), + const_cast(*iObserver->SIPSecUser()))); + CleanupStack::PopAndDestroy(remoteTarget); + HandleSIPSecErrorL(err); + } + + __TEST_INVARIANT; + return ETrue; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::HandleSIPSecErrorL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::HandleSIPSecErrorL(TInt aError) + { + __TEST_INVARIANT; + + if (aError != KErrNone) + { + if (aError != KErrNoMemory) + { + aError = KErrSIPForbidden; + } + Stop(aError); + User::Leave(aError); + } + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SIPSecCacheUpdatedL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::SIPSecCacheUpdatedL(TBool aSuccess, + const CUserAgentState& aResolve, + const CUserAgentState& aWaitResponse, + const CUserAgentState& aWaitAckFromApp, + const CUserAgentState& aWaitTransactionToEnd) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iIncomingMsg, KErrNotFound); + + if (aSuccess) + { + CSIPResponse* resp = static_cast(iIncomingMsg); + iIncomingMsg = NULL; + CleanupStack::PushL(resp); + ReceiveResponseL(resp, + aResolve, + aWaitResponse, + aWaitAckFromApp, + aWaitTransactionToEnd); + CleanupStack::Pop(resp); + } + else + { + Stop(KErrSIPForbidden); + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::ProxyL +// ----------------------------------------------------------------------------- +// +const TDesC8& CUserAgentClient::ProxyL() const + { + __TEST_INVARIANT; + + CURIContainer& nextHop = NextHopL(); + if (iRegistrations.IsOutboundProxy(nextHop)) + { + return CSIPMessageUtility::UriDescriptor(nextHop); + } + return KNullDesC8; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::SendRequestToNetworkL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::SendRequestToNetworkL() + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound); + + CUri8* proxy(NULL); + const CSIPRouteHeader* route = iRegistrations.OutboundProxy(iRegisterId); + if (route) + { + proxy = route->SIPAddress().URI().CloneAsUri8L(); + } + CleanupStack::PushL(proxy); + + if (CSIPMessageUtility::IsAck(*iOutgoingMsg)) + { + __SIP_ASSERT_LEAVE(iTransmitter, KErrNotFound); + iTransmitter->SendRequestL(static_cast(*iOutgoingMsg), + iRemoteAddr, + iForceUDP, + TransportParams(), + proxy, + this); + CleanupStack::PopAndDestroy(proxy); + } + else + { + __SIP_ASSERT_LEAVE(iTransaction, KErrNotFound); + iTransaction->SendRequestL(static_cast(*iOutgoingMsg), + iRemoteAddr, + iTransportProtocol, + iForceUDP, + TransportParams(), + proxy); + CleanupStack::Pop(proxy); + } + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::PassRespToTransactionOwnerL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::PassRespToTransactionOwnerL(CSIPResponse* aResp, + CUserAgent* aUserAgent, + CUserAgentTimer* aTimer) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(aResp, KErrArgument); + __SIP_ASSERT_LEAVE(!iFinalRespPassed, KErrAlreadyExists); + + if (aResp->ResponseCode() == 100 && !IsInviteUAC()) + { + delete aResp; + } + else + { + TRestoreUaState restoreState(iFinalRespPassed, aUserAgent, aTimer); + CleanupStack::PushL(restoreState.CleanupItem()); + iFinalRespPassed = CSIPMessageUtility::IsFinalResponse(*aResp); + + PassMsgToTransactionOwnerL(aResp); + + CleanupStack::Pop(); // cleanupItem + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::FinalRespPassed +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::FinalRespPassed() const + { + __TEST_INVARIANT; + return iFinalRespPassed; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::PassResponseToSIPSecL +// If no iObserver, ignore response and wait transaction to end. +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::PassResponseToSIPSecL(CSIPResponse& aResp) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iOutgoingMsg && iRemoteTarget, KErrNotFound); + + iResponseReceived = ETrue; + TBool mustWait(EFalse); + + if (UseSIPSec() && CSIPMessageUtility::IsFinalResponse(aResp)) + { + CUri8* remoteTarget = iRemoteTarget->CloneAsUri8L(); + TRAPD(err, mustWait = iSIPSec.ResponseReceivedL(iTransportParams, + aResp, + static_cast(*iOutgoingMsg), + RegistrationId(), + TransactionId(), + iRemoteAddr, + CSIPMessageUtility::UriDescriptor(NextHopL()), + *remoteTarget, + ProxyL(), + const_cast(*iObserver->SIPSecUser()), + *this)); + delete remoteTarget; + if( err != KErrNone ) + { + User::Leave( KErrSIPForbidden ); + } + } + + __TEST_INVARIANT; + return mustWait; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::ShouldUaTryAgainL +// If no iObserver ignore response. If send leaves, ConnectionMgr calls old +// transaction's MReceiverObserver::LeaveOccurred and cleanupItem stops UA. +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::ShouldUaTryAgainL(CSIPResponse* aResp, + const CUserAgentState& aResolve, + const CUserAgentState& aWaitResponse) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(aResp, KErrArgument); + + TBool retry(EFalse); + if (!FinalRespPassed() && iObserver) + { + TStopUserAgent stopUa(TransactionId(), + iTransactionStore, + KErrSIPForbidden); + CleanupStack::PushL(stopUa.CleanupItem()); + + TInt respCode = aResp->ResponseCode(); + if (respCode == 503 || respCode == 408) + { + retry = TryNextAddressL(KErrNone, aResolve, aWaitResponse, aResp); + } + + if ((respCode == 401 || respCode == 407 || respCode == 494) && UseSIPSec()) + { + if(iSipSecError) + { + __SIP_LOG( "Request can't be resubmitted because of insufficient information" ) + } + else if(FillSecurityParamsL()) + { + if (iSIPSecCounter > SIPRequestUtility::EMaxForwardsValue) + { + User::Leave(KErrSIPForbidden); + } + ++iSIPSecCounter; + UpdateAndSendRequestL(aWaitResponse); + delete aResp; + retry = ETrue; + } + } + CleanupStack::Pop(); // cleanupItem + } + + __TEST_INVARIANT; + return retry; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::TransactionEndsWithoutFinalResponseL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::TransactionEndsWithoutFinalResponseL(TInt aReason, + const CUserAgentState& aResolve, + const CUserAgentState& aWaitResponse) + { + __TEST_INVARIANT; + + TStopUserAgent stopUa(TransactionId(), iTransactionStore, KErrNoMemory); + CleanupStack::PushL(stopUa.CleanupItem()); + + TBool retry(EFalse); + if (!IsCanceled()) + { + if (aReason == KErrTimedOut) + { + retry = HandleTimeoutL(aResolve, aWaitResponse); + } + if (aReason == KErrSIPTransportFailure || + aReason == KErrSIPICMPFailure) + { + retry = TryNextAddressL(aReason, aResolve, aWaitResponse); + } + } + + CleanupStack::Pop(); // cleanupItem + if (!retry) + { + Stop(aReason); + } + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::HandleTimeoutL +// If SigComp used, delete the compartment and close TCP connection. +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::HandleTimeoutL(const CUserAgentState& aResolve, + const CUserAgentState& aWaitResponse) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound); + + if (CSIPMessageUtility::HasSigCompParam(NextHopL())) + { + UpdateTransportProtocol(*iOutgoingMsg); + if (iTransportProtocol == SIPStrings::StringF(SipStrConsts::ETCP) || + iTransportProtocol == SIPStrings::StringF(SipStrConsts::ETLS)) + { + iTransmitter->TcpDisconnect(iRemoteAddr, TransportParams()); + } + CSIPURI* uri = NextHopL().SIPURI(); + __SIP_ASSERT_LEAVE(uri, KErrNotFound); + + iSigComp.SendFailedL(iTransportParams.CompartmentId()); + iTransportParams.SetCompartmentId(0); + uri->DeleteParam(SIPStrings::StringF(SipStrConsts::EComp)); + SIPRequestUtility::FillRouteAndRequestUriL( + static_cast(*iOutgoingMsg), + *iRouteSet, + *iRemoteTarget); + UpdateAndSendRequestL(aWaitResponse); + + __TEST_INVARIANT; + return ETrue; + } + + return TryNextAddressL(KErrTimedOut, aResolve, aWaitResponse); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::IgnoreResponseRetransmissionsL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::IgnoreResponseRetransmissionsL() + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(!iTransaction, KErrSIPInvalidTransactionState); + + RemoveFromStore(); + CleanupStack::PushL(this); + + CTransactionBase::TTransactionType taType = + CTransactionBase::KClientTransaction; + if (IsInviteUAC()) + { + taType = CTransactionBase::KClientInviteTransaction; + } + + // Set message NULL, to prevent responses being routed to UAC + iTransactionStore.AddL(TransactionId(), this, NULL, NULL, taType); + CleanupStack::Pop(this); + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::CancelSIPSecRequest +// No __TEST_INVARIANT as destructor may lead here. +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::CancelSIPSecRequest() + { + iIgnoreSIPSecCallback = ETrue; + iSIPSec.CancelPendingOperations(*this); + iIgnoreSIPSecCallback = EFalse; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::TryNextAddressL +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::TryNextAddressL(TInt aError, + const CUserAgentState& aResolve, + const CUserAgentState& aWaitResponse, + CSIPResponse* aResp) + { + __TEST_INVARIANT; + __SIP_INT_LOG1( "CUserAgentClient TryNextAddressL Error", + aError ) + __SIP_ASSERT_LEAVE((aError != KErrNone && !aResp) || + (aError == KErrNone && aResp), KErrArgument); + + if (SelectNextRemoteAddressL()) + { + UpdateAndSendRequestL(aWaitResponse); + delete aResp; + return ETrue; + } + + if (iResolvingResults->ContinueResolvingCurrentUri()) + { + __SIP_ASSERT_LEAVE(!iIncomingMsg, KErrAlreadyExists); + + UpdateAndResolveL(ETrue, aResolve); + iLastError = aError; + iIncomingMsg = aResp; + return ETrue; + } + + if (iLastError != KErrNone) + { + aError = iLastError; + } + + // If a stored response exists, next hop has responded. + // Stateless proxy can result KErrTimedOut if its next hop doesn't respond, + // even if the proxy is ok. So URIFailed isn't used for KErrTimedOut. + if ((aError == KErrSIPTransportFailure || + aError == KErrSIPResolvingFailure || + aError == KErrSIPICMPFailure) && + !iIncomingMsg && !iResponseReceived) + { + iRegistrations.URIFailed(NextHopL()); + // Registrations may've used ClearTransactionOwner, stopping UA + if (HasStopped()) + { + return EFalse; + } + } + + TBool retry = TryOutboundProxyL(aResolve); + if (retry) + { + delete aResp; + } + __TEST_INVARIANT; + return retry; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::TryOutboundProxyL +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::TryOutboundProxyL(const CUserAgentState& aResolve) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iRouteSet && iRemoteTarget && iRequestUri, KErrNotFound); + + const CSIPRouteHeader* proxy = iRegistrations.OutboundProxy(iRegisterId); + if (iRouteSet->PreconfigRouteExists() && + !iOutboundProxyHasBeenTried && proxy) + { + const CURIContainer& proxyUri = proxy->SIPAddress().URI(); + + if ( !((NextHopL() == proxyUri) || proxyUri == *iRequestUri) ) + { + iRouteSet->AddToBeginningL(*proxy, EFalse /* append */); + SIPRequestUtility::FillRouteAndRequestUriL( + static_cast(*iOutgoingMsg), + *iRouteSet, + *iRemoteTarget); + UpdateAndResolveL(ETrue, aResolve); + iOutboundProxyHasBeenTried = ETrue; + + __TEST_INVARIANT; + return ETrue; + } + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::DetachCurrentTransactionL +// Request must've been updated or there'd be 2 transactions with a same branch +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::DetachCurrentTransactionL() + { + __TEST_INVARIANT; + + if (iTransaction) + { + if (iTransaction->HasTerminated()) + { + // Cancel transaction's send so new transaction can send + iTransmitter->Cancel(); + RequestDeletionOfTransactionL(); + RemoveFromStore(); + } + else + { + TTransactionId newId = iTransactionStore.NewTransactionId(); + PrepareTxForNewRequestL(newId); + User::LeaveIfError(iTransactionStore.UpdateTransactionId( + TransactionId(), newId)); + if (IsInviteUAC()) + { + __SIP_INT_LOG2( "TU taID changed, old -> new", + TransactionId(), newId ) + } + iTransaction->DetachFromUserAgent(); + iTransaction->ClearSendBuffer(); + iTransaction = NULL; + + iTransactionStore.ClearUserAgent(newId); + } + + CleanupStack::PushL(this); + __SIP_ASSERT_LEAVE(!iTransaction, KErrAlreadyExists); + __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound); + + iTransactionStore.AddL(TransactionId(), + this, + iTransaction, + iOutgoingMsg, + CSIPMessageUtility::TransactionType(*iOutgoingMsg, EFalse)); + CleanupStack::Pop(this); + } + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::UpdateAndSendRequestL +// ----------------------------------------------------------------------------- +// +void +CUserAgentClient::UpdateAndSendRequestL(const CUserAgentState& aWaitResponse) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound); + + UpdateViaAndCSeqL(); + if (!CSIPMessageUtility::IsAck(*iOutgoingMsg)) + { + DetachCurrentTransactionL(); + CreateTransactionL(); + } + + UpdateInfoToStoreL(static_cast(iOutgoingMsg)); + SendRequestToNetworkL(); + ChangeState(aWaitResponse); + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::UpdateAndResolveL +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::UpdateAndResolveL(TBool aCheckSigComp, + const CUserAgentState& aResolve) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(iOutgoingMsg, KErrNotFound); + + UpdateViaAndCSeqL(); + DetachCurrentTransactionL(); + UpdateInfoToStoreL(static_cast(iOutgoingMsg)); + ResolveNextHopL(aCheckSigComp); + ChangeState(aResolve); + + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::StopWithLastError +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::StopWithLastError() + { + __TEST_INVARIANT; + + if (iIncomingMsg) + { + CSIPMessage* msg = iIncomingMsg; + iIncomingMsg = NULL; + TRAPD(err, PassMsgToTransactionOwnerL(msg)); + if (err != KErrNone) + { + delete msg; + } + } + else + { + if (iLastError == KErrNone) + { + // Resolving URI for the first time fails + iLastError = KErrSIPResolvingFailure; + } + } + Stop(iLastError); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::DetachOutgoingMsg +// If transaction can't proceed w/o the message, terminate it silently. +// ----------------------------------------------------------------------------- +// +void CUserAgentClient::DetachOutgoingMsg() + { + __TEST_INVARIANT; + + iOutgoingMsg = NULL; + iTransmitter->Cancel(); + CancelSIPSecRequest(); + + if (iTransaction && !iTransaction->ClearSendBuffer()) + { + iTransaction->DetachFromUserAgent(); + iTransaction->Terminated(); + } + else + { + if (State().CanContinueWithoutOutgoingMsg(iFinalRespPassed)) + { + return; + } + } + + Stop(KErrNone); + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::UseSIPSec +// ----------------------------------------------------------------------------- +// +TBool CUserAgentClient::UseSIPSec() const + { + __TEST_INVARIANT; + return (iObserver && + iObserver->SIPSecUser() && + !iObserver->SIPSecUser()->ByPassSIPSec()); + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::NextHopIP +// ----------------------------------------------------------------------------- +// +const TInetAddr& CUserAgentClient::NextHopIP() const + { + return iRemoteAddr; + } + +// ----------------------------------------------------------------------------- +// CUserAgentClient::__DbgTestInvariant +// ----------------------------------------------------------------------------- +// + +void CUserAgentClient::__DbgTestInvariant() const + { + if ((iOutgoingMsg && !iOutgoingMsg->IsRequest()) || + (iIncomingMsg && iIncomingMsg->IsRequest()) || + (iSIPSecCounter > SIPRequestUtility::EMaxForwardsValue + 1) || + !iResolvingResults) + { + User::Invariant(); + } + }