diff -r 000000000000 -r dfb7c4ff071f datacommsserver/esockserver/ssock/ss_connselect.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/datacommsserver/esockserver/ssock/ss_connselect.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,744 @@ +// Copyright (c) 1997-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: +// SS_CONN.CPP +// +// +#include "ss_connselect.h" + +#include +#include "SS_conn.H" +#include +#include + +#include +#include + +#include +#include +#include + + +#ifdef _DEBUG +// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module +// (if it could happen through user error then you should give it an explicit, documented, category + code) +_LIT(KSpecAssert_ESockSSockscnslc, "ESockSSockscnslc"); +#endif + +using namespace ESock; +using namespace Messages; +using namespace MeshMachine; + +// +//CSelectionRequest +CSelectionRequest* CSelectionRequest::NewL(const TRuntimeCtxId& aRequestingClient, const TNodeId& aTierManagerId) + { + CSelectionRequest* self = new (ELeave) CSelectionRequest(aRequestingClient,aTierManagerId); + + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::NewL")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x]"), self)); + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag(), aRequestingClient, _L8("Client:")); + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag(), aTierManagerId, _L8("TierMgr:")); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + return self; + } + +CSelectionRequest::CSelectionRequest(const TRuntimeCtxId& aRequestingClient, const TNodeId& aTierManagerId) +: Messages::ASimpleNodeIdBase(), + TIfStaticFetcherNearestInHierarchy(this), + iTierManagerId(aTierManagerId), + iSelectionStatus(EIdle), + iPlatsecApiExt(NULL) + { + LOG_NODE_CREATE(KESockMetaConnectionTag, CSelectionRequest); + iRequestingNode.Open(address_cast(aRequestingClient)); + iRequest.Open(iRequestingNode, aRequestingClient); + } + +CSelectionRequest::~CSelectionRequest() + { + if (iPlatsecApiExt != NULL) + delete iPlatsecApiExt; + + + iRequestingNode.Close(); + + //Properly handled CSR should either complete the request or be cancelled before being destroyed. + //If the requesting client wants to cancel its request with this CSR, it sends a cancel message. + //The cancel message is processed (all active requests are being cancelled) and when all complete + //with error (or select complete) messages, then the error is being send to the requesting client. + //The requesting client must wait for this error (confirmation to its cancel message) and then + //it can destroy this CSR, not earlier. + //This is why we must make sure that iActiveRequests is empty. + //If this ASSERT fires in your case, make sure that the requesting client obeys the above mentioned + //protocol. + __ASSERT_DEBUG(iActiveRequests.Count()==0, User::Panic(KSpecAssert_ESockSSockscnslc, 1)); + iActiveRequests.Close(); + + //The client decided to destroy us. + //Regardless if we received or didn't receive TSelect, iTopMcprId must be empty now. + __ASSERT_DEBUG(iTopMcprId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 2)); + LOG_NODE_DESTROY(KESockMetaConnectionTag, CSelectionRequest); + } + +//The entry point to the selector. It may be replaced by the mesh machine in the future. +void CSelectionRequest::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& /*aRecipient*/, TSignatureBase& aCFMessage) + { + if (TEBase::ERealmId == aCFMessage.MessageId().Realm()) + { + switch (aCFMessage.MessageId().MessageId()) + { + case TEBase::TCancel::EId : + __ASSERT_DEBUG(iRequestingNode == aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 3)); + Cancel(); + break; + case TEBase::TError::EId: + { + if (iSelectionStatus==ERequestingCommsBinder) + { + CommsBinderRequestError(aSender, message_cast(aCFMessage)); + } + else + { + TEBase::TError& error = message_cast(aCFMessage); + if (error.iMsgId == TCFSelector::TSimpleSelect::Id() + || error.iMsgId == TCFSelector::TSelect::Id()) + { + //TSelect may be used by CConnection or the TopMcpr + //In both cases the control client must leave on an error. + TInt idx = FindActiveRequest(aSender); + if (idx != KErrNotFound && !(iActiveRequests[idx].Flags() & TClientType::ELeaving)) + { + RNodeInterface::OpenPostMessageClose(Id(), aSender, TEChild::TLeft().CRef()); + iActiveRequests[idx].SetFlags(TClientType::ELeaving); + } + + if (aSender == iTopMcprId) + { + iTopMcprId.SetNull(); + } + } + SelectionError(aSender, error.iValue); + } + } + break; + default: +//TODO - logging + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest:ReceivedL")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x] ERROR: KErrNotSupported "), this)); + NM_LOG_MESSAGE(KESockMetaConnectionTag(), aCFMessage); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + __ASSERT_DEBUG(iRequestingNode==aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 4)); + + __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSockscnslc, 5)); //For debug configurations + User::Leave(KErrNotSupported); //For release configurations + } + } + else if ( aCFMessage.IsMessage() ) + { + __ASSERT_DEBUG(iRequestingNode==aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 6)); + InitialiseDestroy(); + } + else if (TEPeer::ERealmId == aCFMessage.MessageId().Realm()) + { + switch (aCFMessage.MessageId().MessageId()) + { + case TEPeer::TLeaveComplete::EId: + __ASSERT_DEBUG(aSender==iTopMcprId || iTopMcprId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 7)); + iTopMcprId.SetNull(); + delete this; + break; + default: +//TODO - logging + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest:ReceivedL")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x] ERROR: KErrNotSupported "), this)); + NM_LOG_MESSAGE(KESockMetaConnectionTag(), aCFMessage); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSockscnslc, 8)); //For debug configurations + User::Leave(KErrNotSupported); //For release configurations + } + } + else if (TCFSelector::ERealmId == aCFMessage.MessageId().Realm()) + { + switch (aCFMessage.MessageId().MessageId()) + { + case TCFSelector::TSelect::EId: + __ASSERT_DEBUG(aSender == iRequestingNode.RecipientId(), User::Panic(KSpecAssert_ESockSSockscnslc, 9)); + SelectConnPrefList(message_cast(aCFMessage).iConnPrefList); + break; + + case TCFSelector::TSimpleSelect::EId: + __ASSERT_DEBUG(iRequestingNode == aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 10)); + iRequest.Open(iRequestingNode, aSender); + Select(message_cast(aCFMessage).iSelectionPrefs); + break; + case TCFSelector::TSelectComplete::EId: + { + TCFSelector::TSelectComplete& msg = message_cast(aCFMessage); + SelectComplete(address_cast(aSender), msg.iNodeId, msg.iProviderInfo); + } + break; + default: +//TODO - logging + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest:ReceivedL")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x] ERROR: KErrNotSupported "), this)); + NM_LOG_MESSAGE(KESockMetaConnectionTag(), aCFMessage); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSockscnslc, 11)); //For debug configurations + User::Leave(KErrNotSupported); //For release configurations + } + } + else if ( aCFMessage.IsMessage() ) + { + CommsBinderResponse(message_cast(aCFMessage)); + } + else if ( aCFMessage.IsMessage() ) + { + __ASSERT_DEBUG(KErrNone==message_cast(aCFMessage).iValue || iRequestingNode==aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 12)); + __ASSERT_DEBUG(KErrNone==message_cast(aCFMessage).iValue || iSelectionStatus==ERequestingCommsBinder || iSelectionStatus==EIdle, User::Panic(KSpecAssert_ESockSSockscnslc, 13)); + __ASSERT_DEBUG(KErrNone==message_cast(aCFMessage).iValue || !iTopMcprId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 14)); //iTopMcprId must be selected by now! + RNodeInterface::OpenPostMessageClose(Id(), iTopMcprId, aCFMessage); + } + else if ( aCFMessage.IsMessage() ) + { + if (!iDestroying) + { + // When destroying prevent the status change being posted to + // the Implicit Flow Request which may already have been deleted. + iRequestingNode.PostMessage(Id(), aCFMessage); + } + } + else if ( aCFMessage.IsMessage() ) + { + __ASSERT_DEBUG(iRequestingNode == aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 15)); + Provision(message_cast(aCFMessage).iPtr); + } + else if ( aCFMessage.IsMessage() ) + { + JoinComplete(address_cast(aSender), message_cast(aCFMessage)); + } + else + { +//TODO - logging + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest:ReceivedL")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x] ERROR: KErrNotSupported "), this)); + NM_LOG_MESSAGE(KESockMetaConnectionTag(), aCFMessage); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSockscnslc, 16)); //For debug configurations + User::Leave(KErrNotSupported); //For release configurations + } + } + +void CSelectionRequest::InitialiseDestroy() + { + __ASSERT_DEBUG(!iDestroying, User::Panic(KSpecAssert_ESockSSockscnslc, 17)); + iDestroying = ETrue; + + //We are not ready to destruct ourselves yet, waiting for TErrors + if (iActiveRequests.Count()!=0) + { + return; + } + + //We have never joined the top mcpr, clear it now + if (!iJoined) + { + iTopMcprId.SetNull(); + } + + //We are ready but we have to leave the iTopMcprId first + if (!iTopMcprId.IsNull()) + { + RNodeInterface::OpenPostMessageClose(Id(), iTopMcprId, TEPeer::TLeaveRequest().CRef()); + return; + } + + //We are ready to be deleted + delete this; + return; + } + +//Selection requests start here. +void CSelectionRequest::Select(const TSelectionPrefs& aSelectionPreferences) + { + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::Select")); + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag(), iRequestingNode.RecipientId(), _L8("Client:")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x]"), this)); + NM_LOG_STMT(TUint selectionScope = aSelectionPreferences.Scope()); + NM_LOG((KESockMetaConnectionTag(), _L8("%s"), (selectionScope & TSelectionPrefs::EExplicitConnection)?_S8("EExplicitConnection"):_S8("SelectTopProviderOnly"))); + + LOG( ESockLog::Printf(KESockMetaConnectionTag, _L8("CSelectionRequest %08x:\tSelect: %s."), this, (selectionScope&TSelectionPrefs::ESelectFromExisting)?_S8("ESelectFromExisting"):_S8("SelectAndCreate"))); + LOG( ESockLog::Printf(KESockMetaConnectionTag, _L8("CSelectionRequest %08x:\tSelect: %s."), this, (selectionScope&TSelectionPrefs::ERequestCommsBinder)?_S8("ERequestCommsBinder"):_S8("DoNotRequestCommsBinder"))); + + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + //The requesting client may only request selection once. + //If this assert fires in your case, please make sure the requesting client obeys the protocol. + __ASSERT_DEBUG(iSelectionStatus==EIdle, User::Panic(KSpecAssert_ESockSSockscnslc, 18)); + __ASSERT_DEBUG(iTopMcprId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 19)); + iSelectionStatus = ESelecting; + iSelectionPreferences.Copy(aSelectionPreferences); + __ASSERT_DEBUG(iActiveRequests.Count()==0, User::Panic(KSpecAssert_ESockSSockscnslc, 20)); + if (KErrNone==iActiveRequests.Append(RNodeInterface())) + { + RNodeInterface& tierManager = iActiveRequests[0]; + tierManager.Open(iTierManagerId); + tierManager.PostMessage(Id(), TCFPeer::TJoinRequest(Id(), TClientType(TCFClientType::ECtrl)).CRef()); + } + else + { + //We have an OOM condition here. Since we have just started serving this request, + //we must report this error to the requesting client (see SelectError()). + SelectionError(Id(), KErrNoMemory); + } + } + +void CSelectionRequest::SelectConnPrefList(const RConnPrefList& aConnPrefList) + { + //The requesting client may only request selection once. + //If this assert fires in your case, please make sure the requesting client obeys the protocol. + __ASSERT_DEBUG(iSelectionStatus == EIdle, User::Panic(KSpecAssert_ESockSSockscnslc, 21)); + __ASSERT_DEBUG(iTopMcprId == TNodeId::NullId(), User::Panic(KSpecAssert_ESockSSockscnslc, 22)); + iSelectionStatus = ESelecting; + iConnPrefList = aConnPrefList; + + ESock::RConnPrefList::TIter iterCSR = iConnPrefList.getIter(); + //There should be one and only one CSR pref + __ASSERT_DEBUG(iterCSR[0] != NULL || iterCSR[1] == NULL , User::Panic(KSpecAssert_ESockSSockscnslc, 23)); + TConnCSRPref* pref = iterCSR[0]; + iSelectionPreferences.SetScope(pref->Scope()); + iSelectionPreferences.SetFlags(pref->Flags()); + iSelectionPreferences.SetSubSessionUniqueId(pref->Scope()); + + __ASSERT_DEBUG(iActiveRequests.Count()==0, User::Panic(KSpecAssert_ESockSSockscnslc, 24)); + if (KErrNone==iActiveRequests.Append(RNodeInterface())) + { + RNodeInterface& tierManager = iActiveRequests[iActiveRequests.Count()-1]; + tierManager.Open(iTierManagerId); + tierManager.PostMessage( + Id(), + TCFPeer::TJoinRequest(Id(), TClientType(TCFClientType::ECtrl)).CRef() + ); + } + else + { + //We have an OOM condition here. Since we have just started serving this request, + //we must report this error to the requesting client (see SelectError()). + SelectionError(Id(), KErrNoMemory); + } + } + +void CSelectionRequest::Provision(const Meta::SMetaData* aProvisionConfig) + { +/* if (!aProvisionConfig->IsTypeOf(STypeId::CreateSTypeId(CConnectionInfo::EUid, CConnectionInfo::ETypeId))) + return;*/ + iProvision = aProvisionConfig; + } + +void CSelectionRequest::Cancel() + { + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::Cancel")); + NM_LOG((KESockMetaConnectionTag, _L8("[this=0x%08x]"), this)); + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag(), iRequestingNode.RecipientId(), _L8("Client:")); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + //Is the requesting client trying to cancel its request again? + __ASSERT_DEBUG(iSelectionStatus!=ECancelling, User::Panic(KSpecAssert_ESockSSockscnslc, 25)); + if (iSelectionStatus!=EIdle) + { + iSelectionStatus = ECancelling; + iOriginalError = KErrCancel; + + TEBase::TCancel cancel; + for (TInt i = iActiveRequests.Count()-1; i >= 0; i--) + { + //Send cancel and wait for error messages before destructing this object. + iActiveRequests[i].PostMessage(Id(), cancel); + } + //We have not completed the original request yet, do not send + //an error message to the requesting client from here. + //When the last error (or select complete) message has been returned + //from the last MCpr we have cancelled, then we send our cancel's + //confirmation from SelectionFinished(). + } + } + +void CSelectionRequest::JoinComplete(const TNodeId& aSender, TCFPeer::TJoinComplete& /*aCFMessage*/) + { + if (KErrNone==iOriginalError) + { + if (iTopMcprId.IsNull()) + { + __ASSERT_DEBUG(iActiveRequests[0].RecipientId()==aSender && iTierManagerId==aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 26)); //It has surely been sent by the tier manager. + + if(iConnPrefList.Count() < 1) + { + iActiveRequests[0].PostMessage(Id(), TCFSelector::TSimpleSelect(iSelectionPreferences).CRef()); + } + else + { + iActiveRequests[0].PostMessage(Id(), TCFSelector::TSelect(iConnPrefList).CRef()); + } + } + else + { + if (aSender==iTopMcprId) + { + iJoined = ETrue; + + TUint selectionScope = iSelectionPreferences.Scope(); + if (!(selectionScope & TSelectionPrefs::EExplicitConnection)) + { + return; + } + } + + if(iConnPrefList.Count() < 1) + { + RNodeInterface::OpenPostMessageClose(Id(), aSender, TCFSelector::TSimpleSelect(iSelectionPreferences).CRef()); + } + else + { + RNodeInterface::OpenPostMessageClose( + Id(), + aSender, + TCFSelector::TSelect(iConnPrefList).CRef() + ); + } + } + } + else + { + TInt idx = FindActiveRequest(aSender); + if (idx != KErrNotFound && !(iActiveRequests[idx].Flags() & TClientType::ELeaving)) + { + RNodeInterface::OpenPostMessageClose(Id(), aSender, TEChild::TLeft().CRef()); + iActiveRequests[idx].SetFlags(TClientType::ELeaving); + } + + ProviderSelectionFinished(aSender); + + if (iActiveRequests.Count()==0) + { //The active list is empty which means that we have finished serving the selection request. + SelectionFinished(); + } + } + } + +void CSelectionRequest::CommsBinderResponse(const TCFServiceProvider::TCommsBinderResponse& aMsg) + { + iRequest.ReplyTo(Id(), TCFDataClient::TBindTo(aMsg.iNodeId).CRef()); + iSelectionStatus = EIdle; + } + +//This fn is called when a provider has been successfuly selected. +void CSelectionRequest::SelectComplete(const TNodeId& aSenderId, const TNodeId& aMcprId, const TProviderInfo& aMcprInfo) + { + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::SelectComplete")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x]"), this)); + NM_LOG_ADDRESS(KESockMetaConnectionTag(), aSenderId); + NM_LOG_ADDRESS(KESockMetaConnectionTag(), aMcprId); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + __ASSERT_DEBUG(!aSenderId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 27)); //The sender must exist and be in the active list + + //The sender must be in the active list (or it is the tier manager) + __ASSERT_DEBUG(KErrNotFound!=FindActiveRequest(aSenderId), User::Panic(KSpecAssert_ESockSSockscnslc, 28)); + + if (aMcprId.IsNull()) + { //Last SelectComplete from aSenderId. Remove from the active list. + ProviderSelectionFinished(aSenderId); + } + else + { + HandleProviderSelection(aMcprId); + } + + if (iTopMcprId.IsNull()) + { + //Top provider has been selected (it must not be null since we have received SelectComplete and not Error). + + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag, aMcprId, _L8("Top provider selected: ")); + + //We should have never reveive SelectComplete(NULL) as the only select complete. + //If even one provider cannot be selected we should have received an error message! + __ASSERT_DEBUG(!aMcprId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 30)); + __ASSERT_DEBUG(iActiveRequests[0].RecipientId()==aSenderId, User::Panic(KSpecAssert_ESockSSockscnslc, 29)); //It has surely been sent by the tier manager. + iTopMcprId = aMcprId; + iTopMcprInfo = aMcprInfo; + } + else if (iActiveRequests.Count()==0) + { //The active list is empty which means that we have finished serving the selection request. + SelectionFinished(); + } + } + +//This fn is called when we receive or generate an error during selection. +void CSelectionRequest::SelectionError(const TRuntimeCtxId& aSenderId, TInt aError) + { + //Remember the error because for legacy selection we need to use it + if (KErrNone==iOriginalError) + { + iOriginalError = aError; + } + + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::SelectionError")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x] [aError=%d]"), this, aError)); + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag(), iRequestingNode.RecipientId(), _L8("Client:")); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + __ASSERT_DEBUG(!aSenderId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 31)); //The sender must exist and be in the active list + __ASSERT_DEBUG(iSelectionStatus!=ERequestingCommsBinder, User::Panic(KSpecAssert_ESockSSockscnslc, 32)); + + TInt idx = FindActiveRequest(aSenderId); + if(KErrNotFound != idx) + { + //Rather than leaving the service provider (sender) that has send as the error message, + //we are removing it from our list. Any further comunication with the node could result + //in further errors. + iActiveRequests[idx].Close(); + iActiveRequests.Remove(idx); + } + + //If the active list is empty, we have unsuccessfuly finished the whole selection. + if (iActiveRequests.Count()==0) + { + SelectionFinished(); + } + } + +//This fn is called when we receive an error instead of CommsBinder. +void CSelectionRequest::CommsBinderRequestError(const TRuntimeCtxId& aSenderId, TEBase::TError& aCFMessage) + { + // Preventing unused variable warnings. + #ifndef _DEBUG + (void)aSenderId; + #endif + + //Remember the error because for legacy selection we need to use it + if (KErrNone==iOriginalError) + { + iOriginalError = aCFMessage.iValue; + } + + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::CommsBinderRequestError")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x]"), this)); + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag(), iRequestingNode.RecipientId(), _L8("Client:")); + NM_LOG_MESSAGE(KESockMetaConnectionTag(), aCFMessage); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + + __ASSERT_DEBUG(!aSenderId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 33)); //The sender must exist and be in the active list + __ASSERT_DEBUG(iSelectionStatus==ERequestingCommsBinder, User::Panic(KSpecAssert_ESockSSockscnslc, 34)); + __ASSERT_DEBUG(aSenderId==iTopMcprId, User::Panic(KSpecAssert_ESockSSockscnslc, 35)); //CommsBinder error, this can only come from the iTopMcprId + //This is an error that needs to be reported to the requesting client. + PostError(TCFServiceProvider::TCommsBinderRequest::Id(), iOriginalError); + } + +//We call this fn when we need to report the selection error to the originating client, +//but after the selection is finished +void CSelectionRequest::PostError(const TNodeSignal::TMessageId& aMessageId, TInt aError) + { + //Some non-recoverable error has occured and we want to report it back to the requesting client. + + //Because the selection is finished now, there shouldn'd be any more outstanding + //selections going on below. + __ASSERT_DEBUG(iActiveRequests.Count()==0, User::Panic(KSpecAssert_ESockSSockscnslc, 36)); + + iRequest.ReplyTo(Id(), TEBase::TError(aMessageId,aError).CRef()); + } + +void CSelectionRequest::HandleProviderSelection(const TNodeId& aMcprId) + { + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::HandleProviderSelection")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x]"), this)); + NM_LOG_ADDRESS(KESockMetaConnectionTag(), aMcprId); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + + // Select next layer provider only if the selection mode is EExplicitConnection + TUint selectionScope = iSelectionPreferences.Scope(); + if (selectionScope & TSelectionPrefs::EExplicitConnection) + { + //Are we currently waiting for this provider to complete our selection request? + if (KErrNotFound==FindActiveRequest(aMcprId)) + { + if (KErrNone==iActiveRequests.Append(RNodeInterface())) + { + + RNodeInterface& mcpr = iActiveRequests[iActiveRequests.Count()-1]; + mcpr.Open(aMcprId, TClientType(TCFClientType::EServProvider)); + mcpr.PostMessage(Id(), TCFServiceProvider::TJoinRequest(Id(), TClientType::EAdministrative).CRef()); //Join the provider + + } + else + { + //We have an OOM condition here. + SelectionError(Id(), KErrNoMemory); + } + } + } + else if (selectionScope & TSelectionPrefs::ERequestCommsBinder && KErrNone==iOriginalError) + { + __ASSERT_DEBUG(iTopMcprId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 37)); + + RNodeInterface::OpenPostMessageClose(Id(), aMcprId, TCFServiceProvider::TJoinRequest(Id(), TCFClientType::EAdministrative).CRef()); + } + } + +void CSelectionRequest::ProviderSelectionFinished(const TRuntimeCtxId& aMcprId) + { + NM_LOG_START_BLOCK(KESockMetaConnectionTag(), _L8("CSelectionRequest::ProviderSelectionFinished")); + NM_LOG((KESockMetaConnectionTag(), _L8("[this=0x%08x]"), this)); + NM_LOG_ADDRESS_EXT(KESockMetaConnectionTag(), aMcprId, _L8("aMcprId:")); + NM_LOG_END_BLOCK(KESockMetaConnectionTag(), KNullDesC8()); + + TInt idx = FindActiveRequest(aMcprId); + __ASSERT_DEBUG(KErrNotFound!=idx, User::Panic(KSpecAssert_ESockSSockscnslc, 38)); //Sender must be in the active list + + //Leave the providers but do not leave: + //1) The tier manager, as it has never been joined. + //2) The top provider, as it needs to be alive for as long as the requestor is happy to delete us + const TNodeId& selectionProvider = iActiveRequests[idx].RecipientId(); + if (iTopMcprId!=selectionProvider) //Do not leave the top MCpr yet + { + if (idx != KErrNotFound && !(iActiveRequests[idx].Flags() & TClientType::ELeaving)) + { + RNodeInterface::OpenPostMessageClose(Id(), aMcprId, TEChild::TLeft().CRef()); + iActiveRequests[idx].SetFlags(TClientType::ELeaving); + } + } + + //Remove sender from the active list + iActiveRequests[idx].Close(); + iActiveRequests.Remove(idx); + } + +//This fn is called when the whole plane (or just one provider) selection is finished. +//Now we can either start the selected (top) provider or reply to the requesting client +//or just cleanup if the client has cancelled us in the meantime. +void CSelectionRequest::SelectionFinished() + { + LOG(ESockLog::Printf(KESockMetaConnectionTag, _L8("CSelectionRequest::SelectionFinished [this=0x%08x]"), this)); + + if (iSelectionStatus==ECancelling) + { //The requesting client has cancelled us. + LOG(ESockLog::Printf(KESockMetaConnectionTag, _L8("CSelectionRequest::SelectionFinished - cancelled"), this)); + + PostError(TEBase::TCancel::Id(),KErrCancel); + if (!iTopMcprId.IsNull() && iJoined) + { + //We are ready to destroy ourselves now but we have the iTopMcprId to leave first + RNodeInterface::OpenPostMessageClose(Id(), iTopMcprId, TEPeer::TLeaveRequest().CRef()); + } + return; + } + + //We can continue with Starting. + if (KErrNone!=iOriginalError || iTopMcprId.IsNull()) + { + LOG(ESockLog::Printf(KESockMetaConnectionTag, _L8("CSelectionRequest::SelectionFinished - no top provider found"), this)); + + //We don't even have the top provider selected. + //This is an error that needs to be reported to the requesting client. + PostError(TCFSelector::TSimpleSelect::Id(),iOriginalError); + return; + } + + //We can continue with Requesting Comms Binder. + TUint selectionScope = iSelectionPreferences.Scope(); + if (selectionScope & TSelectionPrefs::ERequestCommsBinder) + { + LOG(ESockLog::Printf(KESockMetaConnectionTag, _L8("CSelectionRequest::SelectionFinished - binding to provider (MCpr Tier Id: %X, AP Id: %d)"), this, iTopMcprInfo.TierId().iUid, iTopMcprInfo.APId())); + + TNodeCtxId sender(ECFActivityBinderRequest, Id()); //TODO[PROD]: Does this make sense to use ECFActivityBinderRequest here? + RNodeInterface::OpenPostMessageClose(sender, iTopMcprId, TCFServiceProvider::TCommsBinderRequest().CRef()); + iSelectionStatus = ERequestingCommsBinder; + } + else + { + LOG(ESockLog::Printf(KESockMetaConnectionTag, _L8("CSelectionRequest::SelectionFinished - selected provider (MCpr Tier Id: %X, AP Id: %d)"), this, iTopMcprInfo.TierId().iUid, iTopMcprInfo.APId())); + + //Finish the selection + //We will leave the top provider in ~CSelectionRequest() + iRequest.PostMessage(Id(), TCFSelector::TSelectComplete(iTopMcprId,iTopMcprInfo).CRef()); + } + } + +TInt CSelectionRequest::FindActiveRequest(const TRuntimeCtxId& aMcprId) + { + for (TInt i = iActiveRequests.Count()-1; i >= 0; i--) + { + if (iActiveRequests[i] == aMcprId) + { + return i; + } + } + + return KErrNotFound; + } + +TInt CSelectionRequest::SecureId(TSecureId& aResult) const + { + __ASSERT_DEBUG(iPlatsecApiExt, User::Panic(KSpecAssert_ESockSSockscnslc, 39)); + return iPlatsecApiExt->SecureId(aResult); + } + +TInt CSelectionRequest::VendorId(TVendorId& aResult) const + { + __ASSERT_DEBUG(iPlatsecApiExt, User::Panic(KSpecAssert_ESockSSockscnslc, 40)); + return iPlatsecApiExt->VendorId(aResult); + } + +TBool CSelectionRequest::HasCapability(const TCapability aCapability) const + { + __ASSERT_DEBUG(iPlatsecApiExt, User::Panic(KSpecAssert_ESockSSockscnslc, 41)); + return iPlatsecApiExt->HasCapability(aCapability); + } + +TInt CSelectionRequest::CheckPolicy(const TSecurityPolicy& aPolicy) const + { + __ASSERT_DEBUG(iPlatsecApiExt, User::Panic(KSpecAssert_ESockSSockscnslc, 42)); + return iPlatsecApiExt->CheckPolicy(aPolicy); + } + +NetInterfaces::TInterfaceControl* CSelectionRequest::FetchNodeInterfaceControlL(TInt aInterfaceId) + { + if (aInterfaceId == MPlatsecApiExt::KInterfaceId) + { + if (iPlatsecApiExt) + { + return this; + } + + if (iProvision && iProvision->GetTypeId() == Meta::STypeId::CreateSTypeId(CConnectionInfo::EUid, CConnectionInfo::ETypeId)) + { + iPlatsecApiExt = new(ELeave) ASubSessionPlatsecApiExt(static_cast(iProvision)->SubSessionId()); + return this; + } + } + + return Messages::ANode::FetchNodeInterfaceControlL(aInterfaceId); + } + +void CSelectionRequest::ReturnInterfacePtrL(MPlatsecApiExt*& aInterface) + { + if (iPlatsecApiExt) + aInterface = this; + else + aInterface = NULL; + } +