diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/sipapi/src/SipImplementation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/SIP/sipapi/src/SipImplementation.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,647 @@ +// Copyright (c) 2008-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 : SIPImplementation.cpp +// Part of : SIP API +// Version : SIP/6.0 +// + + + +#include "SipImplementation.h" +#include "SipAssert.h" +#include "sipclient.h" +#include "sipobserver.h" +#include "SipConnectionImplementation.h" +#include "siphttpdigest.h" +#include "unregistered.h" +#include "registering.h" +#include "registered.h" +#include "unregistering.h" +#include "sipdialogtrying.h" +#include "sipdialogearly.h" +#include "sipdialogconfirmed.h" +#include "sipdialogterminated.h" +#include "sipinviteclienttransaction.h" +#include "sipclienttransaction.h" +#include "sipservertransaction.h" +#include "PendingTransaction.h" +#include "siprequestelements.h" +#include "sipresponseelements.h" +#include "sipmessageelements.h" +#include "siphttpdigestchallengeobserver2.h" +#include "sipcseqheader.h" +#include "sipauthheaderbase.h" +#include "sipstrings.h" +#include "sipstrconsts.h" + + +#ifdef CPPUNIT_TEST + +#include "TestCleanupStack.h" + +#endif + + +// ----------------------------------------------------------------------------- +// CSIPImplementation::NewL +// ----------------------------------------------------------------------------- +// +CSIPImplementation* +CSIPImplementation::NewL(const TUid& aUid, MSIPObserver& aObserver) + { + CSIPImplementation* self = new (ELeave) CSIPImplementation(aObserver); + CleanupStack::PushL(self); + self->ConstructL(aUid); + CleanupStack::Pop(self); + return self; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::CSIPImplementation +// ----------------------------------------------------------------------------- +// +CSIPImplementation::CSIPImplementation(MSIPObserver& aObserver) : + iSecurityHandlingEnabled(ETrue), + iObserver(aObserver) +#ifdef CPPUNIT_TEST + //For unit tests the granularity of arrays is set to 1 to cause them to + //allocate memory every time an item is appended to array + , iConnections(1), + iPendingServerTransactions(1), + iDigests(1) +#endif + { + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::ConstructL +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::ConstructL(const TUid& aUid) + { + iSIPClient = CSIPClient::NewL(aUid, *this); + + //Registration state machine + iUnregistered = CUnregistered::NewL(); + iRegistering = CRegistering::NewL(); + iRegistered = CRegistered::NewL(); + iUnregistering = CUnregistering::NewL(); + + iUnregistered->SetNeighbourStates(*iRegistering); + iRegistering->SetNeighbourStates(*iRegistered, *iUnregistered); + iRegistered->SetNeighbourStates(*iUnregistering, *iUnregistered); + iUnregistering->SetNeighbourStates(*iRegistered, *iUnregistered); + + + //Dialog state machine + iDialogTrying = CDialogTrying::NewL(); + iDialogEarly = CDialogEarly::NewL(); + iDialogConfirmed = CDialogConfirmed::NewL(); + iDialogTerminated = CDialogTerminated::NewL(); + + iDialogTrying->SetNeighbourStates(*iDialogEarly, + *iDialogConfirmed, + *iDialogTerminated); + iDialogEarly->SetNeighbourStates(*iDialogConfirmed, + *iDialogTerminated); + iDialogConfirmed->SetNeighbourStates(*iDialogTerminated); + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::~CSIPImplementation +// ----------------------------------------------------------------------------- +// +CSIPImplementation::~CSIPImplementation() + { + delete iSIPClient; + + TInt i = 0; + for (i = 0; i < iPendingServerTransactions.Count(); i++) + { + iPendingServerTransactions[i]->Transaction()->Detach(*this); + } + iPendingServerTransactions.ResetAndDestroy(); + + //Free the array, not the connection objects + for (i = 0; i < iConnections.Count(); i++) + { + iConnections[i]->Implementation().CSIPDeleted(); + } + iConnections.Reset(); + + for (i = 0; i < iDigests.Count(); i++) + { + iDigests[i]->CSIPDeleted(); + } + iDigests.Reset(); + + delete iUnregistered; + delete iRegistering; + delete iRegistered; + delete iUnregistering; + + delete iDialogTrying; + delete iDialogEarly; + delete iDialogConfirmed; + delete iDialogTerminated; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::IncomingRequestL +// Don't use __TEST_INVARIANT after using observer as application may've deleted +// the CSIP within callback. +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::IncomingRequestL(TUint32 aIapId, + CSIPRequestElements* aElements, + TUint32 aRequestId) + { + __TEST_INVARIANT; + __SIP_ASSERT_LEAVE(aElements, KErrArgument); + + CSIPConnection* connection = Connection(aIapId); + if (connection) + { + connection->Implementation().IncomingRequestL(aElements, aRequestId); + } + else + { + CSIPServerTransaction* ta = + CSIPServerTransaction::NewLC(aRequestId, *this, aElements); + CleanupStack::PushL( + TCleanupItem(CSIPServerTransaction::DetachRequestElements, ta)); + CPendingTransaction* pendingTa = CPendingTransaction::NewLC(ta, aIapId); + + iPendingServerTransactions.AppendL(pendingTa); + CleanupStack::Pop(3); //pendingTa, TCleanupItem, ta + + iObserver.IncomingRequest(aIapId, ta); + } + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::TimeOut +// Do everything before calling iObserver.TimedOut() as application may delete +// CSIP withing the callback. +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::TimeOut(TUint32 aRequestId) + { + __TEST_INVARIANT; + + CPendingTransaction* ta = NULL; + for (TInt i = 0; i < iPendingServerTransactions.Count(); i++) + { + ta = iPendingServerTransactions[i]; + __SIP_ASSERT_RETURN(ta && ta->Transaction(), KErrNotFound); + + if (ta->Transaction()->RequestId() == aRequestId) + { + CSIPServerTransaction* timeOutedTa = ta->Transaction(); + timeOutedTa->Detach(*this); + iPendingServerTransactions.Remove(i); + delete ta; + iObserver.TimedOut(*timeOutedTa); + return; + } + } + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::ChallengeReceivedL +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::ChallengeReceivedL( + TUint32 aRequestId, + CSIPResponseElements* aResponse, + MSIPHttpDigestChallengeObserver2& aObserver) + { + __SIP_ASSERT_LEAVE(aResponse != NULL, KErrArgument); + + CSIPClientTransaction* ta(NULL); + for (TInt i = 0; i < iConnections.Count(); ++i) + { + ta = iConnections[i]->Implementation().FindClientTransaction(aRequestId); + if (ta) + { + // Transaction matches aRequestId, so it hasn't yet got response + ta->SetResponseElements(aResponse); + aObserver.ChallengeReceived(*ta); + return; + } + } + + // If dialog's trusted user is a non-refreshed registration and INVITE is + // challenged, INVITE transaction is not found, as ChallengeReceivedL() is + // called in registration's SIP client instance (dialog has another SIP + // client instance). Ignore the challenge, so it gets passed to dialog's + // SIP client. + + // Only one CSIPHttpDigest instance can exist in iDigests + if (iDigests.Count() > 0) + { + ta = CreateTransactionL(aRequestId, aResponse, NULL); + IgnoreChallenges(*ta, *iDigests[0]); + delete ta; + } + else + { + delete aResponse; + } + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::ChallengeReceivedInRefreshL +// Profile sets credentials synchronously. If application sets them +// asynchronously, update code to handle many simultaneous challenges. +// E.g. dialog's trusted user is registration, both REGISTER and INVITE are +// challenged at the same time with different realms. +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::ChallengeReceivedInRefreshL( + TUint32 aRefreshId, + TUint32 aRequestId, + CSIPResponseElements* aResponse, + MSIPHttpDigestChallengeObserver2& aObserver) + { + __SIP_ASSERT_LEAVE(aResponse != NULL, KErrArgument); + + CSIPRefresh* refresh(NULL); + for (TInt i = 0; i < iConnections.Count(); i++) + { + refresh = iConnections[i]->Implementation().FindRefresh(aRequestId, + aRefreshId); + if (refresh) + { + refresh->SetRefreshIdIfEmpty(aRefreshId); + refresh->UpdateRefreshState(aResponse->StatusCode()); + CSIPClientTransaction* ta = refresh->Transaction(); + if (ta) + { + ta->SetResponseElements(aResponse); + aObserver.ChallengeReceived(*refresh); + } + else + { + ta = CreateTransactionL(aRequestId, aResponse, refresh); + aObserver.ChallengeReceived(*refresh); + + // INVITE transaction doesn't point to refresh. Manually unlink + // transaction and refresh, instead of letting destructor do it + refresh->RemoveTransaction(); + if (ta->Refresh()) + { + ta->RemoveRefresh(); + } + delete ta; + } + return; + } + } + delete aResponse; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::SupportedSecurityMechanismsL +// ----------------------------------------------------------------------------- +// +CDesC8Array* CSIPImplementation::SupportedSecurityMechanismsL() const + { + __TEST_INVARIANT; + return iSIPClient->SupportedSecurityMechanismsL(); + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::IsSigCompSupportedL +// ----------------------------------------------------------------------------- +// +TBool CSIPImplementation::IsSigCompSupportedL() const + { + __TEST_INVARIANT; + return iSIPClient->IsSigCompSupportedL(); + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::NegotiatedSecurityMechanismL +// ----------------------------------------------------------------------------- +// +HBufC8* +CSIPImplementation::NegotiatedSecurityMechanismL(const TDesC8& aHop) const + { + __TEST_INVARIANT; + return iSIPClient->NegotiatedSecurityMechanismL(aHop); + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::Connection +// ----------------------------------------------------------------------------- +// +CSIPConnection* CSIPImplementation::Connection(TUint32 aIapId) const + { + __TEST_INVARIANT; + + for (TInt i = 0; i < iConnections.Count(); i++) + { + if (iConnections[i]->IapId() == aIapId) + { + return iConnections[i]; + } + } + return NULL; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::SetSecurityHandlingL +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::SetSecurityHandlingL(TBool aEnabled) + { + __TEST_INVARIANT; + iSIPClient->SetSecurityHandlingL(aEnabled); + iSecurityHandlingEnabled = aEnabled; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::IsSecurityHandlingEnabled +// ----------------------------------------------------------------------------- +// +TBool CSIPImplementation::IsSecurityHandlingEnabled() const + { + __TEST_INVARIANT; + return iSecurityHandlingEnabled; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::CreateTransactionL +// It doesn't matter what MTransactionAssociation is given to NewL. +// ----------------------------------------------------------------------------- +// +CSIPClientTransaction* +CSIPImplementation::CreateTransactionL(TUint32 aRequestId, + CSIPResponseElements* aResponse, + CSIPRefresh* aRefresh) + { + __SIP_ASSERT_LEAVE(aResponse && aResponse->CSeqHeader(), KErrNotFound); + + CSIPClientTransaction* ta(NULL); + RStringF method = aResponse->CSeqHeader()->Method(); + if (method == SIPStrings::StringF(SipStrConsts::EInvite)) + { + ta = CSIPInviteClientTransaction::NewL(*this); + if (aRefresh) + { + // Links refresh to INVITE transaction, but not the other way + aRefresh->AddTransaction(*ta); + } + } + else + { + ta = CSIPClientTransaction::NewL(method, *this, aRefresh); + } + ta->SetRequestId(aRequestId); + ta->SetResponseElements(aResponse); + return ta; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::IgnoreChallenges +// ----------------------------------------------------------------------------- +// +void +CSIPImplementation::IgnoreChallenges( const CSIPClientTransaction& aTransaction, + CSIPHttpDigest& aDigest ) + { + const CSIPResponseElements* resp = aTransaction.ResponseElements(); + if ( resp ) + { + const RPointerArray& headers = + resp->MessageElements().UserHeaders(); + + RStringF wwwAuth = + SIPStrings::StringF(SipStrConsts::EWWWAuthenticateHeader); + RStringF proxyAuth = + SIPStrings::StringF(SipStrConsts::EProxyAuthenticateHeader); + RStringF realm = SIPStrings::StringF(SipStrConsts::ERealm); + + for (TInt i = 0; i < headers.Count(); ++i) + { + const CSIPHeaderBase* header = headers[i]; + if (header->Name() == wwwAuth || header->Name() == proxyAuth) + { + const CSIPAuthHeaderBase* auth = + static_cast(header); + aDigest.IgnoreChallenge(aTransaction, + auth->DesParamValue(realm)); + } + } + } + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::SIPClient +// ----------------------------------------------------------------------------- +// +CSIPClient& CSIPImplementation::SIPClient() + { + __TEST_INVARIANT; + return *iSIPClient; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::AddConnectionL +// CSIPClient checks if a connection for the IAP-id already exists. No need to +// do it here. +// +// Associate server transactions with the same IAP-id (aIapId), to aConnection. +// Start search from the end of array, so if an item is removed, it doesn't +// affect the position of items that haven't yet been checked. +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::AddConnectionL( + CSIPConnectionImplementation& aConnImplementation, + TUint32 aIapId) + { + __TEST_INVARIANT; + + CSIPConnection& conn = aConnImplementation.SIPConnectionL(); + iConnections.AppendL(&conn); + + CPendingTransaction* ta(NULL); + for (TInt i = iPendingServerTransactions.Count(); i > 0; i--) + { + ta = iPendingServerTransactions[i - 1]; + __SIP_ASSERT_LEAVE(ta, KErrNotFound); + + if (ta->IapId() == aIapId) + { + ta->Transaction()->ReAssociateL(aConnImplementation); + } + } + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::RemoveConnection +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::RemoveConnection(const CSIPConnection& aConnection) + { + __TEST_INVARIANT; + + TInt pos = iConnections.Find(&aConnection); + if (pos != KErrNotFound) + { + iConnections.Remove(pos); + } + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::RemoveConnection +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::AddDigestL(CSIPHttpDigest& aDigest) + { + __TEST_INVARIANT; + + iDigests.AppendL(&aDigest); + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::RemoveDigest +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::RemoveDigest(const CSIPHttpDigest& aDigest) + { + __TEST_INVARIANT; + + TInt pos = iDigests.Find(&aDigest); + if (pos != KErrNotFound) + { + iDigests.Remove(pos); + } + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::ClientConnectionL +// CSIPImplementation doesn't know which CSIPClientConnection to return since +// no IAP-id is passed as parameter. +// ----------------------------------------------------------------------------- +// +CSIPClientConnection& CSIPImplementation::ClientConnectionL() + { + __TEST_INVARIANT; + + User::Leave(KErrUnknown); + return *(CSIPClientConnection*)1; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::ClientConnection +// CSIPImplementation doesn't know which CSIPClientConnection to return since +// no IAP-id is passed as parameter. +// ----------------------------------------------------------------------------- +// +CSIPClientConnection* CSIPImplementation::ClientConnection() + { + __TEST_INVARIANT; + return NULL; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::SIPConnectionL +// CSIPImplementation doesn't know which CSIPConnection to return since no +// IAP-id is passed as parameter. +// ----------------------------------------------------------------------------- +// +CSIPConnection& CSIPImplementation::SIPConnectionL() + { + __TEST_INVARIANT; + + User::Leave(KErrUnknown); + return *(CSIPConnection*)1; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::AddTransactionL +// ----------------------------------------------------------------------------- +// +void CSIPImplementation::AddTransactionL(CSIPTransactionBase& /*aTransaction*/) + { + // No action + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::RemoveTransaction +// ----------------------------------------------------------------------------- +// +void +CSIPImplementation::RemoveTransaction(const CSIPTransactionBase& aTransaction) + { + __TEST_INVARIANT; + + CPendingTransaction* ta(NULL); + for (TInt i = 0; i < iPendingServerTransactions.Count(); i++) + { + ta = iPendingServerTransactions[i]; + __SIP_ASSERT_RETURN(ta && ta->Transaction(), KErrNotFound); + + if (ta->Transaction() == &aTransaction) + { + iPendingServerTransactions.Remove(i); + delete ta; + return; + } + } + __TEST_INVARIANT; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::InitialRegisterState +// ----------------------------------------------------------------------------- +// +CRegistrationState* CSIPImplementation::InitialRegisterState() + { + __TEST_INVARIANT; + return iUnregistered; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::InitialDialogState +// ----------------------------------------------------------------------------- +// +CDialogState* CSIPImplementation::InitialDialogState() + { + __TEST_INVARIANT; + return iDialogTrying; + } + +// ----------------------------------------------------------------------------- +// CSIPImplementation::__DbgTestInvariant +// ----------------------------------------------------------------------------- +// + + +void CSIPImplementation::__DbgTestInvariant() const + { + if (!iSIPClient || + !iUnregistered || !iRegistering || !iRegistered || !iUnregistering || + !iDialogTrying || !iDialogEarly || !iDialogConfirmed || + !iDialogTerminated) + { + User::Invariant(); + } + }