datacommsserver/esockserver/ssock/ss_connselect.cpp
changeset 0 dfb7c4ff071f
child 14 8b5d60ce1e94
--- /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 <comms-infras/ss_log.h>
+#include "SS_conn.H"
+#include <comms-infras/esock_params_internal.h>
+#include <comms-infras/ss_nodemessages_selector.h>
+
+#include <elements/nm_messages_base.h>
+#include <elements/nm_messages_peer.h>
+
+#include <comms-infras/ss_nodemessages_dataclient.h>
+#include <comms-infras/ss_nodemessages_factory.h>
+#include <comms-infras/ss_nodemessages_internal.h>
+
+
+#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<TNodeId>(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<TEBase::TError>(aCFMessage));
+				}
+			else
+				{
+				TEBase::TError& error = message_cast<TEBase::TError>(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<TEChild::TDestroy>() )
+		{
+		__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<const TCFSelector::TSelect>(aCFMessage).iConnPrefList);
+    		break;
+
+		case TCFSelector::TSimpleSelect::EId:
+			__ASSERT_DEBUG(iRequestingNode == aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 10));
+			iRequest.Open(iRequestingNode, aSender);
+			Select(message_cast<const TCFSelector::TSimpleSelect>(aCFMessage).iSelectionPrefs);
+			break;
+		case TCFSelector::TSelectComplete::EId:
+			{
+			TCFSelector::TSelectComplete& msg = message_cast<TCFSelector::TSelectComplete>(aCFMessage);
+			SelectComplete(address_cast<TNodeId>(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<TCFServiceProvider::TCommsBinderResponse>() )
+		{
+		CommsBinderResponse(message_cast<TCFServiceProvider::TCommsBinderResponse>(aCFMessage));
+		}
+	else if ( aCFMessage.IsMessage<TCFDataClient::TBindToComplete>() )
+		{
+		__ASSERT_DEBUG(KErrNone==message_cast<TCFDataClient::TBindToComplete>(aCFMessage).iValue || iRequestingNode==aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 12));
+		__ASSERT_DEBUG(KErrNone==message_cast<TCFDataClient::TBindToComplete>(aCFMessage).iValue || iSelectionStatus==ERequestingCommsBinder || iSelectionStatus==EIdle, User::Panic(KSpecAssert_ESockSSockscnslc, 13));
+		__ASSERT_DEBUG(KErrNone==message_cast<TCFDataClient::TBindToComplete>(aCFMessage).iValue || !iTopMcprId.IsNull(), User::Panic(KSpecAssert_ESockSSockscnslc, 14)); //iTopMcprId must be selected by now!
+		RNodeInterface::OpenPostMessageClose(Id(), iTopMcprId, aCFMessage);
+		}
+	else if ( aCFMessage.IsMessage<TCFMessage::TStateChange>() )
+		{
+		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<TCFMessage::TProvisionConnectionInfo>() )
+		{
+		__ASSERT_DEBUG(iRequestingNode == aSender, User::Panic(KSpecAssert_ESockSSockscnslc, 15));
+		Provision(message_cast<const TCFMessage::TProvisionConnectionInfo>(aCFMessage).iPtr);
+		}
+	else if ( aCFMessage.IsMessage<TCFPeer::TJoinComplete>() )
+		{
+		JoinComplete(address_cast<TNodeId>(aSender), message_cast<TCFPeer::TJoinComplete>(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<TConnCSRPref> iterCSR = iConnPrefList.getIter<TConnCSRPref>();
+	//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<const CConnectionInfo*>(iProvision)->SubSessionId());
+            return this;
+        	}
+    	}
+
+	return Messages::ANode::FetchNodeInterfaceControlL(aInterfaceId);
+	}
+
+void CSelectionRequest::ReturnInterfacePtrL(MPlatsecApiExt*& aInterface)
+	{
+	if (iPlatsecApiExt)
+		aInterface = this;
+	else
+		aInterface = NULL;
+	}
+