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) 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<CSIPRequest*>(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<MTransactionUser::KCallIDLength> 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<KBranchLength> 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<CSIPRequest&>(*iOutgoingMsg),
RegistrationId(),
TransactionId(),
iRemoteAddr,
CSIPMessageUtility::UriDescriptor(NextHopL()),
*remoteTarget,
ProxyL(),
const_cast<MSIPSecUser&>(*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<CSIPResponse*>(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<CSIPRequest&>(*iOutgoingMsg),
iRemoteAddr,
iForceUDP,
TransportParams(),
proxy,
this);
CleanupStack::PopAndDestroy(proxy);
}
else
{
__SIP_ASSERT_LEAVE(iTransaction, KErrNotFound);
iTransaction->SendRequestL(static_cast<CSIPRequest&>(*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<CSIPRequest&>(*iOutgoingMsg),
RegistrationId(),
TransactionId(),
iRemoteAddr,
CSIPMessageUtility::UriDescriptor(NextHopL()),
*remoteTarget,
ProxyL(),
const_cast<MSIPSecUser&>(*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<CSIPRequest&>(*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<CSIPRequest&>(*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<CSIPRequest*>(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<CSIPRequest*>(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();
}
}