--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/TransactionUser/src/UserAgent.cpp Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,786 @@
+// Copyright (c) 2007-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 : UserAgent.cpp
+// Part of : TransactionUser
+// Version : SIP/6.0
+//
+
+
+
+#include "siperr.h"
+#include "SipAssert.h"
+#include "siprequest.h"
+#include "sipresponse.h"
+#include "sipuri.h"
+#include "uricontainer.h"
+#include "siphostport.h"
+#include "sipaddress.h"
+#include "sipfromtoheaderbase.h"
+#include "sipcontactheader.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+#include "SipLogs.h"
+#include "DeleteMgr.h"
+#include "Transmitter.h"
+
+#include "MSipRegistrationContact.h"
+#include "MTransactionOwner.h"
+#include "CUserAgent.h"
+#include "UserAgentState.h"
+#include "UserAgentCreateParams.h"
+#include "CTransactionStore.h"
+#include "SIPMessageUtility.h"
+#include "MTransactionUser.h"
+
+
+// -----------------------------------------------------------------------------
+// CUserAgent::CUserAgent
+// aObserver is NULL for UAS
+// -----------------------------------------------------------------------------
+//
+CUserAgent::CUserAgent(const CUserAgentCreateParams& aParams) :
+ iObserver(aParams.iObserver),
+ iTimers(aParams.iTimers),
+ iRegistrations(aParams.iRegistrations),
+ iRegistrationContact(aParams.iRegistrationContact),
+ iSigComp(aParams.iSigComp),
+ iTransactionStore(aParams.iTransactionStore),
+ iTransactionMgr(aParams.iTransactionMgr),
+ iTransportProtocol(SIPStrings::StringF(SipStrConsts::EUDP)),
+ iTransportParams(aParams.iTransportParams),
+ iTimerValues(aParams.iTimerValues),
+ iOwnsOutgoingMsg(aParams.iOwnsOutgoingMsg),
+ iDeleteMgr(aParams.iDeleteMgr),
+ iSIPMsgUtility(aParams.iSIPMsgUtility),
+ iState(aParams.iInitialUaState),
+ iTransactionId(aParams.iTransactionId)
+ {
+ __SIP_ASSERT_RETURN(iTransactionId != KEmptyTransactionId, KErrArgument);
+ __SIP_ASSERT_RETURN(iState != NULL, KErrArgument);
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::ConstructL(MSipConnectionMgr& aConnectionMgr)
+ {
+ iTransmitter = CTransmitter::NewL(aConnectionMgr);
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::~CUserAgent
+// -----------------------------------------------------------------------------
+//
+CUserAgent::~CUserAgent()
+ {
+ delete iTransmitter;
+ delete iTransaction;
+
+ if (iOwnsOutgoingMsg)
+ {
+ delete iOutgoingMsg;
+ }
+
+ delete iIncomingMsg;
+ iTransportProtocol.Close();
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::TransportParams
+// -----------------------------------------------------------------------------
+//
+const TSIPTransportParams& CUserAgent::TransportParams() const
+ {
+ __TEST_INVARIANT;
+ return iTransportParams;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::CleanupSilently
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::CleanupSilently(TAny* aUserAgent)
+ {
+ __SIP_ASSERT_RETURN(aUserAgent, KErrArgument);
+
+ CUserAgent* ua = reinterpret_cast<CUserAgent*>(aUserAgent);
+ ua->ClearTransactionOwner(); // Prevent MTransactionOwner::TransactionEnded
+ ua->Stop(KErrGeneral); // End silently, error code doesn't matter
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::SendRequestL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::SendRequestL(CSIPRequest* aReq,
+ TRegistrationId aRegisterId,
+ const CURIContainer& aRemoteTarget)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aReq, KErrArgument);
+ __ASSERT_ALWAYS(!iStopped, User::Leave(KErrSIPInvalidTransactionState));
+
+ iState->SendRequestL(*this, aReq, aRegisterId, aRemoteTarget);
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::SendResponseL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::SendResponseL(CSIPResponse* aResp,
+ const TSIPTransportParams& aParams)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aResp, KErrArgument);
+ __ASSERT_ALWAYS(!iStopped, User::Leave(KErrSIPInvalidTransactionState));
+
+ iState->SendResponseL(*this, aResp, aParams);
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::SendCancelL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::SendCancelL(TTransactionId aInviteTaId)
+ {
+ __TEST_INVARIANT;
+ __ASSERT_ALWAYS(!iStopped, User::Leave(KErrSIPInvalidTransactionState));
+
+ iState->SendCancelL(*this, aInviteTaId);
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::TransactionOwner
+// -----------------------------------------------------------------------------
+//
+const MTransactionOwner* CUserAgent::TransactionOwner() const
+ {
+ __TEST_INVARIANT;
+ return iObserver;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::ClearTransactionOwner
+// Detach iOutgoingMsg unless owned, as the upper layer can delete it.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::ClearTransactionOwner()
+ {
+ __TEST_INVARIANT;
+
+ iObserver = NULL;
+
+ if (!iOwnsOutgoingMsg)
+ {
+ DetachOutgoingMsg();
+ }
+
+ if (iState->ShouldUASStop())
+ {
+ Stop(KErrNone);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::DetachOutgoingMsg
+// No action.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::DetachOutgoingMsg()
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::ReceiveL
+// Write request to log, if it came directly from ConnectionMgr.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::ReceiveL(CSIPRequest* aRequest)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aRequest, KErrArgument);
+
+ if (iStopped)
+ {
+ delete aRequest;
+ }
+ else
+ {
+ if (!iTransaction)
+ {
+ __SIP_MESSAGE_LOG("TransactionUser", *aRequest)
+ }
+
+ iState->ReceiveL(*this, aRequest);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::ReceiveL
+// Write response to log, if it came directly from ConnectionMgr.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::ReceiveL(CSIPResponse* aResponse)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aResponse, KErrArgument);
+
+ if (iStopped)
+ {
+ delete aResponse;
+ }
+ else
+ {
+ if (!iTransaction)
+ {
+ __SIP_MESSAGE_LOG("TransactionUser", *aResponse)
+ }
+
+ iState->ReceiveL(*this, aResponse);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::LeaveOccurred
+// If Dialog drops a response, it leaves with KErrSIPInvalidDialogResponse.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::LeaveOccurred(TInt aReason)
+ {
+ __TEST_INVARIANT;
+
+ __SIP_INT_LOG1( "CUser Agent :: LeaveOccured with reason",
+ aReason )
+
+ if (aReason != KErrSIPInvalidDialogResponse)
+ {
+ Stop(aReason);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::SendCompleteL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::SendCompleteL()
+ {
+ __TEST_INVARIANT;
+
+ if (!iStopped)
+ {
+ iState->SendCompleteL(*this);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::SendFailedL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::SendFailedL(TInt aError)
+ {
+ __TEST_INVARIANT;
+ __SIP_INT_LOG1( "CUserAgent Sending failed with Error",
+ aError )
+
+ if (!iStopped)
+ {
+ iState->SendFailedL(*this, aError);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::LeaveFromTransmitter
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::LeaveFromTransmitter(TInt aReason)
+ {
+ __TEST_INVARIANT;
+ __ASSERT_DEBUG(aReason != KErrNone,
+ User::Panic(_L("UA:LeaveFromTransmitter"), KErrArgument));
+ Stop(aReason);
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::TimerExpiredL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::TimerExpiredL(TTimerId aTimerId, TAny* aTimerParam)
+ {
+ __TEST_INVARIANT;
+
+ if (!iStopped)
+ {
+ iState->TimerExpiredL(*this, aTimerId, aTimerParam);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::DeleteTimer
+// The concrete UA must implement DeleteTimer.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::DeleteTimer(const CUserAgentTimer& /*aTimer*/)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_RETURN(EFalse, KErrGeneral);
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::StoreOutgoingMsg
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::StoreOutgoingMsg(CSIPMessage* aMsg)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_RETURN(aMsg, KErrArgument);
+
+ if (iOwnsOutgoingMsg)
+ {
+ delete iOutgoingMsg;
+ }
+
+ iOutgoingMsg = aMsg;
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::IsInviteUAC
+// -----------------------------------------------------------------------------
+//
+TBool CUserAgent::IsInviteUAC() const
+ {
+ __TEST_INVARIANT;
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::IsSubInviteUAC
+// Don't call __TEST_INVARIANT here to avoid recursion
+// -----------------------------------------------------------------------------
+//
+TBool CUserAgent::IsSubInviteUAC() const
+ {
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::State
+// -----------------------------------------------------------------------------
+//
+const CUserAgentState& CUserAgent::State() const
+ {
+ __TEST_INVARIANT;
+ return *iState;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::ChangeState
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::ChangeState(const CUserAgentState& aNewState)
+ {
+ __TEST_INVARIANT;
+
+ iState = &aNewState;
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::IsResolving
+// -----------------------------------------------------------------------------
+//
+TBool CUserAgent::IsResolving() const
+ {
+ __TEST_INVARIANT;
+ return iState->IsResolving();
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::UpdateTransactionOwner
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::UpdateTransactionOwner(MTransactionOwner* aNewObserver)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_RETURN(aNewObserver, KErrArgument);
+
+ iObserver = aNewObserver;
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::TransactionEndsL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::TransactionEndsL(TInt aReason)
+ {
+ __TEST_INVARIANT;
+
+ iState->TransactionEndsL(*this, aReason);
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::PassMsgToTransactionOwnerL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::PassMsgToTransactionOwnerL(CSIPMessage* aMsg) const
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aMsg, KErrArgument);
+
+ if (iObserver)
+ {
+ __SIP_INT_LOG1( "TU passes SIP message to owner, transaction ID",
+ iTransactionId )
+
+ if (aMsg->IsRequest())
+ {
+ CSIPRequest* request = static_cast<CSIPRequest*>(aMsg);
+
+ __SIP_DES8_LOG( "TU SIP request method",
+ request->Method().DesC() )
+ iObserver->ReceiveL(iTransportParams.IapId(),
+ iTransactionId,
+ request);
+ }
+ else
+ {
+ CSIPResponse* response = static_cast<CSIPResponse*>(aMsg);
+
+ __SIP_INT_LOG1( "TU SIP response code",
+ response->ResponseCode() )
+ iObserver->ReceiveL(iTransactionId, response);
+ }
+ }
+ else
+ {
+ __SIP_INT_LOG1(
+ "TU msg not passed to owner, iObserver==NULL, transaction ID",
+ iTransactionId )
+
+ delete aMsg;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::UpdateTransportProtocol
+// -----------------------------------------------------------------------------
+//
+TBool CUserAgent::UpdateTransportProtocol(CSIPMessage& aMsg)
+ {
+ __TEST_INVARIANT;
+ return CSIPMessageUtility::TransportProtocol(aMsg, iTransportProtocol);
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::AddTagL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::AddTagL(CSIPFromToHeaderBase& aToFromHeader) const
+ {
+ __TEST_INVARIANT;
+
+ TBuf8<MTransactionUser::KTagLength> tagBuf;
+ AddRandomStringL(tagBuf, MTransactionUser::KTagLength, EFalse);
+
+ RStringF tag = SIPStrings::Pool().OpenFStringL(tagBuf);
+ CleanupClosePushL(tag);
+ aToFromHeader.SetParamL(SIPStrings::StringF(SipStrConsts::ETag), tag);
+ CleanupStack::PopAndDestroy(); // tag
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::AddRandomStringL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::AddRandomStringL(TDes8& aBuf,
+ TInt aLength,
+ TBool aCaseSensitive) const
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aLength <= aBuf.MaxLength() - aBuf.Length(),
+ KErrArgument);
+
+ iSIPMsgUtility.AddRandomStringL(aBuf,
+ aLength,
+ aCaseSensitive,
+ iOutgoingMsg,
+ iTransactionId,
+ this);
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::IcmpErrorL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::IcmpErrorL(const TInetAddr& aAddress,
+ CSipConnectionMgr::TICMPError aError)
+ {
+ __TEST_INVARIANT;
+
+ if (!iStopped)
+ {
+ iState->IcmpErrorL(*this, aAddress, aError);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::CheckContactHeadersL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::CheckContactHeadersL(CSIPMessage& aMsg,
+ const CSIPFromToHeaderBase* aFromToHeader) const
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aFromToHeader != NULL, KErrArgument);
+
+ const RStringF KContact = SIPStrings::StringF(SipStrConsts::EContactHeader);
+ if (aMsg.HasHeader(KContact))
+ {
+ TSglQueIter<CSIPHeaderBase> iter = aMsg.Headers(KContact);
+ for (CSIPHeaderBase* header = iter++; header; header = iter++)
+ {
+ CSIPContactHeader* contact =
+ static_cast<CSIPContactHeader*>(header);
+ if (!contact->Star())
+ {
+ __SIP_ASSERT_LEAVE(contact->SIPAddress(), KErrArgument);
+ if (contact->SIPAddress()->URI().IsSIPURI())
+ {
+ CSIPURI* sipUri = contact->SIPAddress()->URI().SIPURI();
+ if (sipUri->HostPort().Host().CompareF(
+ SIPStrings::StringF(SipStrConsts::ELocalHost).DesC())
+ == 0)
+ {
+ iRegistrationContact.ContactL(iTransportParams.IapId(),
+ RegistrationId(),
+ aFromToHeader,
+ static_cast<CSIPContactHeader&>(*header));
+ }
+ CheckSigCompL(contact->SIPAddress()->URI());
+ }
+ }
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::RemoveFromStore
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::RemoveFromStore() const
+ {
+ __TEST_INVARIANT;
+
+ iTransactionStore.Remove(iTransactionId);
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::RequestDeletionOfTransactionL
+// Leave if AddDeleteRequest fails. Don't change TransactionId, to avoid using
+// RequestDeletionOfUserAgent after changing id. Changing id twice fails causing
+// "delete this" and call stack likely has UA/transaction code, causing a crash.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::RequestDeletionOfTransactionL()
+ {
+ __TEST_INVARIANT;
+
+ if (iTransaction)
+ {
+ User::LeaveIfError(iDeleteMgr.AddDeleteRequest(iTransaction));
+ iTransaction = NULL;
+ iTransactionStore.ClearTransaction(iTransactionId);
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::RequestDeletionOfUserAgent
+// -----------------------------------------------------------------------------
+//
+TInt CUserAgent::RequestDeletionOfUserAgent()
+ {
+ __TEST_INVARIANT;
+
+ TInt status = iDeleteMgr.AddDeleteRequest(this);
+ if (status == KErrNone)
+ {
+ // DeleteMgr took UA's ownership
+ RemoveFromStore();
+ }
+ else
+ {
+ // Other errors mean e.g. trying to delete object twice
+ if (status == KErrNoMemory)
+ {
+ // Set id empty, to be freed later. Fails if UA isn't stored, but it
+ // occurs only in CTransactionUser::SendL/SendAndGetHeadersL/
+ // SendCancelL so UA isn't in call stack, and can "delete this".
+ status = iTransactionStore.UpdateTransactionId(iTransactionId,
+ KEmptyTransactionId);
+ if (status != KErrNone)
+ {
+ delete this;
+ return KErrDied; // Skip __TEST_INVARIANT
+ }
+ }
+ }
+
+ __TEST_INVARIANT;
+ return status;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::Stop
+// "sub InviteUAC" doesn't use observer or request its own deletion.
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::Stop(TInt aReason)
+ {
+ __TEST_INVARIANT;
+
+ if (!iStopped)
+ {
+ iStopped = ETrue;
+
+ if (!IsSubInviteUAC())
+ {
+ if (iObserver)
+ {
+ if (IsInviteUAC() && IsCanceled() && aReason == KErrTimedOut)
+ {
+ aReason = KErrCancel;
+ }
+ __SIP_INT_LOG2( "TU TransactionEnded (reason, transaction ID)",
+ aReason, iTransactionId )
+ iObserver->TransactionEnded(iTransportParams.IapId(),
+ iTransactionId,
+ aReason);
+ }
+ else
+ {
+ __SIP_INT_LOG1( "TU UA:Stop(), iObserver==NULL, transaction ID",
+ iTransactionId )
+ }
+
+ if (RequestDeletionOfUserAgent() == KErrDied)
+ {
+ // Skip __TEST_INVARIANT as UA was deleted synchronously
+ return;
+ }
+ }
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::TransactionId
+// -----------------------------------------------------------------------------
+//
+TTransactionId CUserAgent::TransactionId() const
+ {
+ __TEST_INVARIANT;
+ return iTransactionId;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::Transaction
+// -----------------------------------------------------------------------------
+//
+CTransactionBase* CUserAgent::Transaction()
+ {
+ __TEST_INVARIANT;
+ return iTransaction;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::CheckSigCompL
+// -----------------------------------------------------------------------------
+//
+void CUserAgent::CheckSigCompL(const CURIContainer& aUri) const
+ {
+ __TEST_INVARIANT;
+
+ if (CSIPMessageUtility::HasSigCompParam(aUri) && !iSigComp.IsSupported())
+ {
+ User::Leave(KErrNotSupported);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::HasStopped
+// -----------------------------------------------------------------------------
+//
+TBool CUserAgent::HasStopped() const
+ {
+ __TEST_INVARIANT;
+ return iStopped;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::IsCanceled
+// -----------------------------------------------------------------------------
+//
+TBool CUserAgent::IsCanceled() const
+ {
+ __TEST_INVARIANT;
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CUserAgent::__DbgTestInvariant
+// -----------------------------------------------------------------------------
+//
+
+void CUserAgent::__DbgTestInvariant() const
+ {
+ if (!iState || !iTransmitter || (IsUAS() && !iOwnsOutgoingMsg))
+ {
+ User::Invariant();
+ }
+ }
+