datacommsserver/esockserver/ssock/ss_conn.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:22:25 +0200
changeset 0 dfb7c4ff071f
child 1 21d2ab05f085
permissions -rw-r--r--
Revision: 200951 Kit: 200951

// Copyright (c) 2005-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:
//

/**
 @file
 @internalTechnology
*/

#define SYMBIAN_NETWORKING_UPS

#include <comms-infras/ss_log.h>
#include <comms-infras/ss_nodemessages.h>
#include <comms-infras/ss_nodemessages_serviceprovider.h>
#include <comms-infras/ss_nodemessages_factory.h>
#include <comms-infras/ss_nodemessages_subconn.h>
#include "SS_conn.H"
#include "ss_connstates.h"
#include <comms-infras/ss_datamonitoringprovider.h>
#include <comms-infras/ss_roles.h>
#include <ss_glob.h>

#include <comms-infras/ss_coreprstates.h>
#include <comms-infras/ss_corepractivities.h>

#include <elements/sm_core.h>
#include <comms-infras/es_parameterbundle.h>
#include <comms-infras/es_commsdataobject.h>
#include <comms-infras/ss_commsdataobject.h>
#include <nifman.h>
#include <comms-infras/nifprvar.h>

#include <in_sock.h> //KAfInet only

#include <elements/nm_signatures.h>

#include <comms-infras/ss_msgintercept.h>

#ifdef SYMBIAN_NETWORKING_UPS
#include <comms-infras/upsmessages.h>		// reference from ESock to UpsCoreProviders - should we move the UPS messages into ESock?
#endif

#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)
// UNCOMMENT IF INSERTING AN ASSERT
//_LIT(KSpecAssert_ESockSSocks_cn, "ESockSSocks_cn.");
#endif



using namespace ESock;
using namespace SubSessActivities;
using namespace NetStateMachine;
using namespace ConnActivities;
using namespace SubSessStates;
using namespace CoreStates;
using namespace Elements;
using namespace Messages;
using namespace MeshMachine;
using namespace Den;

//We reserve space for two preallocated activities that may start concurrently on the connection
//node: destroy (connection close) and connection stop.
static const TUint KDefaultMaxPreallocatedActivityCount = 2;
static const TUint KMaxPreallocatedActivitySize = sizeof(CNodeRetryParallelActivity) + sizeof(APreallocatedOriginators<4>);
static const TUint KConnectionPreallocatedActivityBufferSize = KDefaultMaxPreallocatedActivityCount * KMaxPreallocatedActivitySize;

//
//Activities serving client (RConnection) requests
namespace ConnectionStartActivity
{
 //Synchronised activity, must wait for stop (exclusive with close)
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityStart, ConnectionStart, TCFInternalEsock::TSubSess, ConnActivities::CStartAttachActivity::NewStartConnectionActivityL)
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ECNStart>, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, MeshMachine::TNoTag)
	
	// If the IPC was ECNSetStartPrefs we expect another IPC to start the connection 
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessStartBlockedByStop, ConnActivities::CStartAttachActivity::TNoTagOrStartPrefsSetTag)
	NODEACTIVITY_ENTRY(ConnActivities::CStartAttachActivity::KStartPrefsSetTag, MeshMachine::TDoNothing, SubSessStates::TAwaitingIPC<ECNStart>, ConnActivities::CStartAttachActivity::TStartPrefsSetTag)
	THROUGH_NODEACTIVITY_ENTRY(ConnActivities::CStartAttachActivity::KStartPrefsSetTag, SubSessStates::TAcquireMessageOwnership, ConnActivities::CStartAttachActivity::TStartPrefsSetTag)
	THROUGH_NODEACTIVITY_ENTRY(ConnActivities::CStartAttachActivity::KStartPrefsSetTag, ConnStates::TParseECNStart, MeshMachine::TNoTag)
	
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TClearProgressQueue, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TSendStartingSelectionStateChange, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TRequestCSRCreation, TECABState<CoreNetStates::TAwaitingCSRCreated>, MeshMachine::TNoTag)
	

	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessCSRCreation, MeshMachine::TNoTag)

	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TSelectMetaPlane, ConnActivities::CStartAttachActivity::TAwaitingSelectCompleteOrError, MeshMachine::TNoTagOrErrorTag)
	LAST_NODEACTIVITY_ENTRY(KErrorTag, MeshMachine::TDoNothing)

	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TJoinReceivedMcpr, TECABState<CoreStates::TAwaitingJoinComplete>, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TRequestCommsBinderFromMcpr, TAcceptErrorState<CoreNetStates::TAwaitingBinderResponse>, MeshMachine::TNoTagOrErrorTag)
	LAST_NODEACTIVITY_ENTRY(KErrorTag, CoreActivities::ABindingActivity::TSendBindToComplete) //Terminate the activity
	
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TSendFinishedSelectionStateChange, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessBinderResponseForCpr, TECABState<CoreStates::TAwaitingJoinComplete>, MeshMachine::TNoTag)

#ifdef SYMBIAN_NETWORKING_UPS
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnActivities::CStartAttachActivity::TSendBindToComplete, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, CStartAttachActivity::TSendPolicyCheckRequestToServiceProvider, TAcceptErrorState<TAwaitingMessageState<UpsMessage::TPolicyCheckResponse> >, CStartAttachActivity::TNoTagOrUpsErrorTag)
  	//<legacy begin> - requesting and joining the default scpr just to satisfy the subconn related datamonitoring API.
  	//If the default scpr isn't there, we'll ignore the error here but we will dissallow subscribing to subcon-related data monitoring.
  	NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TRequestCommsBinder, TAcceptErrorState<CoreNetStates::TAwaitingBinderResponse>, MeshMachine::TNoTagOrErrorTag)
 #endif


#ifndef SYMBIAN_NETWORKING_UPS
  	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnActivities::CStartAttachActivity::TSendBindToComplete, MeshMachine::TNoTag)
  	NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TRequestCommsBinder, TAcceptErrorState<CoreNetStates::TAwaitingBinderResponse>, MeshMachine::TNoTagOrErrorTag)
#endif


  	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TJoinReceivedSCpr, TECABState<CoreStates::TAwaitingJoinComplete>, MeshMachine::TNoTag)
  	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CoreActivities::ABindingActivity::TSendBindToComplete, MeshMachine::TNoTag)
  	// Act on cancellation errors, ignore all others.
  	ROUTING_NODEACTIVITY_ENTRY(KErrorTag, ConnStates::TErrorOrCancel)
  	THROUGH_NODEACTIVITY_ENTRY(KErrorTag, MeshMachine::TClearError, MeshMachine::TNoTag)
  	//</legacy end>>

	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnActivities::CStartAttachActivity::TSubscribeForAvailability, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, ConnActivities::CStartAttachActivity::TNoTagOrWaitAvailable)
	NODEACTIVITY_ENTRY(ConnActivities::CStartAttachActivity::KWaitAvailable, MeshMachine::TDoNothing, ConnActivities::CStartAttachActivity::TAwaitingAvailableOrError, MeshMachine::TNoTag)

	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TStartConnection, TAcceptErrorState<CoreNetStates::TAwaitingStarted>, CoreStates::TCancelOrErrorOrTag<KNoTag>)
	// Handle error during start
	THROUGH_NODEACTIVITY_ENTRY(KErrorTag, ConnStates::TGenerateConnectionDownProgress, ConnActivities::CStartAttachActivity::TErrorTagOrWaitAvailableBackward)
	
	LAST_NODEACTIVITY_ENTRY(KNoTag,  ConnStates::TGenerateConnectionUpProgress )

	// Handle error during start.
	THROUGH_NODEACTIVITY_ENTRY(ConnActivities::CStartAttachActivity::KCancelTag, MeshMachine::TDoNothing, MeshMachine::TErrorTag)	// just a tag
#ifdef SYMBIAN_NETWORKING_UPS
	THROUGH_NODEACTIVITY_ENTRY(CStartAttachActivity::KUpsErrorTag, TDoNothing, MeshMachine::TErrorTag)
#endif
	NODEACTIVITY_ENTRY(KErrorTag, CoreNetStates::TSendClientLeavingRequestToServiceProviders, MeshMachine::TAwaitingLeaveComplete, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TSetIdleIfNoServiceProviders, MeshMachine::TAwaitingLeaveComplete, ConnectionCleanupActivities::TNoTagOrNoTagBackwards)
	LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
NODEACTIVITY_END()
}

namespace ConnectionAttachActivity
{
typedef SubSessStates::TAwaitingSecuredIpc<SubSessStates::TAwaitingIPC<ECNAttach>, ECapabilityNetworkServices> TAwaitingSecuredAttachIpc;

//Synchronised activity, must wait for stop (exclusive with close)
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionAttach, ConnectionAttach, TCFInternalEsock::TSubSess, ConnActivities::CStartAttachActivity::NewStartConnectionActivityL)
#ifdef SYMBIAN_NETWORKING_UPS
	// UPS support.  Platform Security check now takes place in the Cpr as part of the control client join activity.
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ECNAttach>, MeshMachine::TNoTag)
#else
	FIRST_NODEACTIVITY_ENTRY(TAwaitingSecuredAttachIpc, MeshMachine::TNoTag)
#endif
	// NOTE: TAcquireMessageOwnership MUST occur before any blocking takes place, otherwise the Player will
	// complete the message upon return from the blocked activity.
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, CoreNetStates::TNoTagBlockedByStop)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessAttachBlockedByStop, TECABState<CoreNetStates::TAwaitingCSRCreated>, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessCSRCreation, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TSelectMetaPlane, ConnActivities::CStartAttachActivity::TAwaitingSelectCompleteOrError, MeshMachine::TNoTagOrErrorTag)
	LAST_NODEACTIVITY_ENTRY(KErrorTag, MeshMachine::TDoNothing)

	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TJoinReceivedMcpr, TECABState<CoreStates::TAwaitingJoinComplete>, MeshMachine::TNoTag)
    NODEACTIVITY_ENTRY(KNoTag, ConnStates::TRequestCommsBinderFromMcpr, TAcceptErrorState<CoreNetStates::TAwaitingBinderResponse>, MeshMachine::TNoTagOrErrorTag)
	LAST_NODEACTIVITY_ENTRY(KErrorTag, CoreActivities::ABindingActivity::TSendBindToComplete) //Terminate the activity

    NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessBinderResponseForCpr, TECABState<CoreStates::TAwaitingJoinComplete>, CStartAttachActivity::TNoTagOrLegacyAttach)

    //New Attach - go here
	LAST_NODEACTIVITY_ENTRY(KNoTag, ConnActivities::CStartAttachActivity::TSendBindToComplete)
	//Legacy Attach - go here
	LAST_NODEACTIVITY_ENTRY(CStartAttachActivity::KExecuteLegacyAttach, ConnActivities::CStartAttachActivity::TSendBindToCompleteAndCompleteLegacyAttach)
NODEACTIVITY_END()
}

namespace ConnectionStopActivity
{
//Synchronised activity, must wait for start to finish
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityStop, ConnectionStop, TCFInternalEsock::TSubSess, CPreallocatedESockClientActivity::New)
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ECNStop>, MeshMachine::TNoTag)
	// NOTE: TAcquireMessageOwnership MUST occur before any blocking takes place, otherwise the Player will
	// complete the message upon return from the blocked activity.
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, CoreNetStates::TActiveOrNoTagBlockedByGoneDown)
	THROUGH_NODEACTIVITY_ENTRY(KActiveTag, ConnStates::TCancelStartOrAttachConnection, ConnStates::TNoTagOrNoBearerBlockedByStartOrAttach)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TCancelAndCloseZone0ClientExtIfaces, MeshMachine::TNoTag)
    THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TCancelAllLegacyRMessage2Activities, ConnStates::TNoTagBlockedByLegacyRMessage2Activities)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TSendStopConnection, TECABState<CoreNetStates::TAwaitingStopped>, MeshMachine::TNoTag)
    THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TGenerateConnectionDownProgress, MeshMachine::TNoTag)

	NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TSendClientLeavingRequestToServiceProviders, MeshMachine::TAwaitingLeaveComplete, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TSetIdleIfNoServiceProviders, MeshMachine::TAwaitingLeaveComplete, ConnectionCleanupActivities::TNoTagOrNoTagBackwards)
	
	LAST_NODEACTIVITY_ENTRY(CoreNetStates::KNoBearer, MeshMachine::TDoNothing)
	LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
NODEACTIVITY_END()
}

/**
	Legacy RConnection::Stop(TSubConnectionUniqueId aSubConnectionUniqueId) implementation
*/
namespace ConnectionStopSCPRActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityStopSCPR, ConnectionStopSCPR, TCFInternalEsock::TSubSess, CESockClientActivityBase::NewL)
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ESCPSStop>, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TConnectionSendStopSCPR, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, TECABState<CoreNetStates::TAwaitingStopped>, MeshMachine::TNoTag)
	LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing)
NODEACTIVITY_END()
}

/**
	Legacy RConnection::EnumerateConnections implementation
*/
namespace EnumerateConnectionsActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionEnumerateConnections, EnumerateConnections, TCFInternalEsock::TSubSess, CEnumerateConnectionsActivity::NewL)
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ECNEnumerateConnections>, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, MeshMachine::TNoTag)

	// Find the tier manager and query it.
	NODEACTIVITY_ENTRY(KNoTag, CTierManagerActivity::TFindTierManager, TECABState<CTierManagerActivity::TAwaitingTierManager>, MeshMachine::TErrorTagOr<MeshMachine::TTag<KNoTag> >)
		LAST_NODEACTIVITY_ENTRY(KErrorTag, MeshMachine::TDoNothing)

	NODEACTIVITY_ENTRY(KNoTag, CTierManagerActivity::TJoinTierManager, TECABState<CoreStates::TAwaitingJoinComplete>, MeshMachine::TNoTag)

	NODEACTIVITY_ENTRY(KNoTag, TQueryTierStatus, TECABState<TAwaitingTierStatus>, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, TCacheConnectionInfo, MeshMachine::TNoTag)

	LAST_NODEACTIVITY_ENTRY(KNoTag, TCompleteClient)
NODEACTIVITY_END()
}

namespace ConnectionGoneUpActivity
{
DECLARE_DEFINE_NODEACTIVITY(ECFActivityAny, ConnectionGoneUp, TCFControlClient::TGoneUp)
	FIRST_NODEACTIVITY_ENTRY(CoreNetStates::TAwaitingGoneUp, MeshMachine::TNoTag)
	LAST_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TGenerateConnectionUpProgress)
NODEACTIVITY_END()
}

namespace ConnectionCloseActivity
{ //Cancells all other running activities
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityDestroy, ConnectionClose, TCFInternalEsock::TSubSess, CCloseActivity::New)
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ECNClose>, MeshMachine::TNoTag)
	// NOTE: TAcquireMessageOwnership MUST occur before any blocking takes place, otherwise the Player will
	// complete the message upon return from the blocked activity.
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, ConnStates::TActiveOrNoTagBlockedByStopOrGoneDown)
	THROUGH_NODEACTIVITY_ENTRY(KActiveTag, ConnStates::TCancelStartOrAttachConnection, ConnStates::TNoTagBlockedByStartOrAttach)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TCancelAndCloseClientExtIfaces, ConnStates::TNoTagOrCancelAllInterfaceWorker)
	// Handshake a shutdown of AllInterfaceNotificationWorker (send TCancel, await TError).
	NODEACTIVITY_ENTRY(ConnStates::KCancelAllInterfaceWorker, ConnStates::TCancelAllInterfaceNotificationWorker, TAwaitingMessageState<TEBase::TError>, MeshMachine::TNoTag)
    THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TCancelAllLegacyRMessage2Activities, ConnStates::TNoTagBlockedByLegacyRMessage2Activities)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessClose, TECABState<MeshMachine::TAwaitingLeaveComplete>, MeshMachine::TNoTag)
	//TDestroyAwaitingLeaveCompleteLoop loops back to its own triple if more SPs
	NODEACTIVITY_ENTRY(KNoTag, TECABTransition<CoreNetStates::TSetIdleIfNoServiceProviders>, TECABState<MeshMachine::TAwaitingLeaveComplete>, CoreActivities::CDestroyActivity::TNoTagOrNoTagBackwards)
	LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing) //Never gets here
NODEACTIVITY_END()
}

namespace ConnectionStateChangeNotificationActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionStateChangeRequest, ConnectionStateChangeNotification, TCFInternalEsock::TSubSess, CESockClientActivityBase::NewL)
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ECNProgressNotification>, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, MeshMachine::TNoTag)
	//TAwaitingStateChangeLoop also cancels the activity when requested
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessProgressRequest, TECABState<MeshMachine::TAwaitingMessageState<TCFMessage::TStateChange> >, 		MeshMachine::TNoTagBackward)
	LAST_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing) //Never gets here
NODEACTIVITY_END()
}

namespace ConnectionWaitForIncomingActivity
{ //Synchronised, waits for Start to complete
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionWaitForIncoming, ConnectionWaitForIncoming, TCFInternalEsock::TSubSess, CStartAttachActivity::NewWaitForIncomingConnectionActivityL)
	FIRST_NODEACTIVITY_ENTRY(SubSessStates::TAwaitingIPC<ECNWaitForIncoming>, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TAcquireMessageOwnership, MeshMachine::TNoTag)
	//We use ConnStates::TAwaitingBinderResponse (not CoreStates) for custom handling of the Cancel message
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TRequestIncomingConnectionBlockedByStartAttach, TECABState<CoreNetStates::TAwaitingBinderResponse>, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessIncomingConnection, TECABState<CoreNetStates::TAwaitingBindToComplete>, MeshMachine::TNoTag)
	LAST_NODEACTIVITY_ENTRY(KNoTag, ConnActivities::CStartAttachActivity::TSendBindToComplete)
NODEACTIVITY_END()
}

//
//Activities serving framework requests
namespace ConnectionStateChangeActivity
{
DECLARE_DEFINE_NODEACTIVITY(ECFActivityStateChange, ConnectionStateChange, TCFMessage::TStateChange)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessStateChange, MeshMachine::TAwaitingMessageState<TCFMessage::TStateChange>, MeshMachine::TNoTag)
NODEACTIVITY_END()
}



namespace ConnectionGoingDownActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityGoneDown, ConnectionGoingDown, TCFControlClient::TGoneDown, PRActivities::CGoneDownActivity::NewL)
	FIRST_NODEACTIVITY_ENTRY(ConnStates::TAwaitingGoneDown, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnectionGoingDownActivity::TStoreGoneDownError, MeshMachine::TNoTag)
	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TCancelAndCloseZone0ClientExtIfaces, MeshMachine::TNoTag)
    THROUGH_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TCancelAllLegacyRMessage2Activities, ConnStates::TNoTagBlockedByLegacyRMessage2Activities)
	NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TSendClientLeavingRequestToServiceProviders, MeshMachine::TAwaitingLeaveComplete, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TSetIdleIfNoServiceProviders, MeshMachine::TAwaitingLeaveComplete, ConnectionCleanupActivities::TNoTagOrNoTagBackwards)
	LAST_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TGenerateConnectionDownProgress)
NODEACTIVITY_END()
}

//
//Activities serving framework requests for legacy actions
namespace ConnectionClientEnumActivity
{
DECLARE_DEFINE_NODEACTIVITY(ECFActivityLegacyConnEnumResponse, ConnectionEnumResponse, TCFInternalEsock::TLegacyConnectionEnumResponse)
	NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessEnumResponse, ConnStates::TAwaitingEnumResponse, MeshMachine::TNoTag)
NODEACTIVITY_END()
}

//
//CConn usually is a cntrl client of a default subconnection.
//The subconnection will send events, which must be handled to avoid leakages
namespace ConnSubConnectionEventNotification
{
DECLARE_DEFINE_NODEACTIVITY(ECFActivityConnectionWaitForIncoming, SubConEvent, TCFSubConnControlClient::TSubConnNotification)
	NODEACTIVITY_ENTRY(KNoTag, SubSessStates::TBinEvent, CoreNetStates::TAwaitingSubConEvent, MeshMachine::TNoTag)
NODEACTIVITY_END()
}

namespace ConnSubConnEventsActivity
{
DECLARE_DEFINE_NODEACTIVITY(ECFActivityConnSubConnEvents, ConnSubConnEvents, TNodeSignal::TNullMessageId)
	NODEACTIVITY_ENTRY(KNoTag, ConnSubConnEventsActivity::TProcessSubConnEvent, ConnSubConnEventsActivity::TAwaitingSubConnEvent, MeshMachine::TNoTag)
NODEACTIVITY_END()
}

namespace ConnLegacyRMessage2Activity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionLegacyRMessage2Handler, ConnectionLegacyRMessage2, TNodeSignal::TNullMessageId, CConnLegacyRMessage2Activity::NewL)
    FIRST_NODEACTIVITY_ENTRY(CoreNetStates::TAwaitingLegacyRMessage2Ext, MeshMachine::TNoTag)
    NODEACTIVITY_ENTRY(KNoTag, ConnStates::TProcessLegacyRMessage2, TAcceptErrorState<CoreNetStates::TAwaitingRMessage2Processed>, MeshMachine::TNoTagOrErrorTag)
    LAST_NODEACTIVITY_ENTRY(KNoTag, ConnStates::TCompleteRMessage2)
    LAST_NODEACTIVITY_ENTRY(KErrorTag, ConnStates::THandleRMessage2Error)
NODEACTIVITY_END()
}

namespace ConnectionActivities
{
DECLARE_DEFINE_ACTIVITY_MAP(connectionActivities)
	//-----Framework originated activities-----//
	ACTIVITY_MAP_ENTRY(ConnectionStateChangeActivity, ConnectionStateChange)
	ACTIVITY_MAP_ENTRY(ConnectionGoingDownActivity, ConnectionGoingDown)
	ACTIVITY_MAP_ENTRY(ConnSubConnectionEventNotification, SubConEvent)
	ACTIVITY_MAP_ENTRY(ConnSubConnEventsActivity, ConnSubConnEvents)
	ACTIVITY_MAP_ENTRY(ConnectionStopSCPRActivity, ConnectionStopSCPR)
	ACTIVITY_MAP_ENTRY(ConnectionGoneUpActivity,ConnectionGoneUp)
	//-----Client (IPC) originated activities-----//
	ACTIVITY_MAP_ENTRY(ConnectionWaitForIncomingActivity, ConnectionWaitForIncoming)
	ACTIVITY_MAP_ENTRY(ConnectionCloseActivity, ConnectionClose)
	ACTIVITY_MAP_ENTRY(ConnectionStartActivity, ConnectionStart)
	ACTIVITY_MAP_ENTRY(ConnectionAttachActivity, ConnectionAttach)
	ACTIVITY_MAP_ENTRY(ConnectionStateChangeNotificationActivity, ConnectionStateChangeNotification)
	ACTIVITY_MAP_ENTRY(ConnectionStopActivity, ConnectionStop)

	ACTIVITY_MAP_ENTRY(ConnLegacyRMessage2Activity, ConnectionLegacyRMessage2)

#ifdef AVAILABILITY_READY
	ACTIVITY_MAP_ENTRY(EnumerateConnectionsActivity, EnumerateConnections)
#endif

	//-----Responses from Data plane to legacy queries-----//
	ACTIVITY_MAP_ENTRY(ConnectionClientEnumActivity, ConnectionEnumResponse)
ACTIVITY_MAP_END()
}

// attribute table for CConnectionIfno
START_ATTRIBUTE_TABLE(CConnectionInfo, CConnectionInfo::EUid, CConnectionInfo::ETypeId)
END_ATTRIBUTE_TABLE()


namespace ESock
{
CConnectionInfo* CConnectionInfo::NewL(const Den::TSubSessionUniqueId& aSubSessionId)
	{
	return new(ELeave) CConnectionInfo(aSubSessionId);
	}
}

/**
Constructor
*/
CConnection::CConnection(CSockSession* aSession, CPlayer* aPlayer, TUid aTierId, const Den::TSubSessionUniqueId aSubSessionUniqueId)
:	CMMSockSubSession(ConnectionActivities::connectionActivities::Self(), aSession, aPlayer, aSubSessionUniqueId),
    ASubSessionPlatsecApiExt(UniqueId()),
    TIfStaticFetcherNearestInHierarchy(this),
    iTierId(aTierId),
    iLegacyConnection(*this)
	{
	LOG_NODE_CREATE1(KESockConnectionTag, CConnection, ", session %08x", aSession);
	}
/**
Destructor
*/
CConnection::~CConnection()
	{
	//Do not call CConnection::FinalCompleteAllBlockedMessages from here!
	//At this stage we must be completed.
	iLegacyConnection.FinalCompleteAllBlockedMessages(KErrCancel); //complete any outstanding legacy messages
	delete iConnectionInfo;
    LOG_NODE_DESTROY(KESockConnectionTag, CConnection);
	}

//MZTODO - only client activities? Is this a shutdown?
//Signal from subsession to abbort all (client?) activities (always KErrAbort)
void CConnection::FinalCompleteAllBlockedMessages(TInt /*aResult*/)
	{
	TNodeNullContext ctx(*this);
	AbortActivitiesOriginatedBy(ctx); //Abort all activities
	iLegacyConnection.FinalCompleteAllBlockedMessages(KErrCancel); //complete any outstanding legacy messages
	}

void CConnection::Received(TNodeContextBase& aContext)
    {
    TNodeSignal::TMessageId noPeerIds[] = {
    	TCFInternalEsock::TSubSess::Id(),
    	TEBase::TError::Id(), //May be comming from the CSR
    	TCFInternalEsock::TLegacyConnectionEnumResponse::Id(),	// self-dispatching helper from the data plane
    	TNodeSignal::TMessageId()	// list terminator
    	};

	MeshMachine::AMMNodeBase::Received(noPeerIds, aContext);
	MeshMachine::AMMNodeBase::PostReceived(aContext);
	}

void CConnection::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aCFMessage)
    {
	ESOCK_DEBUG_MESSAGE_INTERCEPT(aSender, aCFMessage, Id());

	//First check if this is not our own error
	TEBase::TError* msg = message_cast<TEBase::TError>(&aCFMessage);
	if (msg	&& aSender == Id() && msg->iMsgId == TCFInternalEsock::TSubSess::Id())
		{
		//This is our own error, generated from the client (IPC) activity
		//It is safe to just ignore it here, as the activity is
		//completed (and so is the client RMessage2). If the activity didn't have
		//the chance to acquire ownership of the message it is still safe to ignore it
		//because there was no call to DoNotCompleteCurrentMessage().
		return;
		}

	TNodeContext<CConnection> ctx(*this, aCFMessage, aSender, aRecipient);
    CConnection::Received(ctx);
    User::LeaveIfError(ctx.iReturn);
	}

void CConnection::ForwardToServiceProviderL(const TSignalBase& aCFMessage)
	{
	RNodeInterface* sp = ServiceProvider();
	User::LeaveIfError(sp? KErrNone : KErrNotReady);
	sp->PostMessage(Id(), aCFMessage);
	}

CConnection* CConnection::NewLC(CSockSession *aSession, CPlayer* aPlayer, TUid aId, const Den::TSubSessionUniqueId aSubSessionUniqueId)
/**
Create a new CConnection instance

@param aSession Session under which CConnection was created
@param aId Type Id of CConnection
@return pointer to new CConnection instance on success
@exception leaves if could not allocate memory
*/
	{
	CConnection* h = new (ELeave) CConnection(aSession, aPlayer, aId, aSubSessionUniqueId);
	CleanupStack::PushL(h);
	h->ConstructL();
	ESOCK_DEBUG_REGISTER_GENERAL_NODE(ESockDebug::KConnectionNodeUid, h);
	return h;
	}

CConnection* CConnection::NewLC(CSockSession* aSession, CPlayer* aPlayer, const CConnection& aExistingConnection, const Den::TSubSessionUniqueId aSubSessionUniqueId)
/**
Create a new CConnection object associated with the same interface as that of an existing CConnection object.

@param aSession Session under which CConnection was created
@param aExistingConnection Existing CConnection object whose interface to associate with
@return pointer to new CConnection instance on success
@exception leaves if could not allocate memory
*/
	{
	CConnection* h = new (ELeave) CConnection(aSession, aPlayer, aExistingConnection.iTierId, aSubSessionUniqueId);
	CleanupStack::PushL(h);
	h->ConstructL();
	h->CloneL(aExistingConnection);
	return h;
	}

void CConnection::ConstructL()
	{
	MeshMachine::AMMNodeBase::ConstructL(KConnectionPreallocatedActivityBufferSize);
	CSockSubSession::ConstructL(NULL);

	iConnectionInfo = CConnectionInfo::NewL(UniqueId());
	}

void CConnection::CloneL(const CConnection& aExistingConnection)
/**
Main body of CConnection::NewL(CSockSession* aSession, const CConnection& aExistingConnection)
*/
	{
	RNodeInterface* sp = aExistingConnection.ServiceProvider();
	if (sp)
		{
	    AddClientL(sp->RecipientId(), TClientType(TCFClientType::EServProvider, TCFClientType::EActive));

		// TODO IK: This is the wrong message to be using here, should use JoinRequest/Complete handshake
	    sp->PostMessage(Id(), TCFFactory::TPeerFoundOrCreated(Id(), 0).CRef());
        }
	else
		{
		LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x CloneL KErrNotReady"), this) );
		User::Leave(KErrNotReady);
		}
	}


RNodeInterface* CConnection::DefaultSubConnectionServiceProvider()
 	{
 	RNodeInterface* dscp = GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider,TCFClientType::EDefault))[0];
 	return dscp;
 	}

void CConnection::ProcessMessageL()
/**
	Process RConnection messages

	@exception Leaves on any error processing the request
*/
	{
	LOG_DETAILED( ESockLog::Printf(KESockConnectionTag, _L("CConnection %08x:\tCommand %d"), this, aMessage.Function()) );

	//Some of the client (RMessage2) messages may need to be posted, for most it
	//will be sufficient to dispatch them directly via ReceivedL (advantage of posting
	//rather than dispatching -> of course mesh logging!)
	switch (Message().Function())
		{
		case ECNReference:
			GetReferenceL();
			break;

		case ECNStart:
		case ECNSetStartPrefs:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNStart aMessage %08x"), this, &Message()) );
			//If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed on leave
			CMMSockSubSession::ReceivedL(ECNStart, TCFInternalEsock::TSubSess(ECNStart,Message()).CRef());
			break;

		case ECNAttach:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNAttach aMessage %08x"), this, &Message()) );
			//If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed on leave
			CMMSockSubSession::ReceivedL(ECNAttach, TCFInternalEsock::TSubSess(ECNAttach,Message()).CRef());
			break;

		case ECNStop:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNStop aMessage %08x"), this, &Message()) );

			//Legacy support - if there is nothing to stop, return KErrNotReady
			if (ServiceProvider() == NULL && CountActivities(ECFActivityStart) == 0)
				{
				User::Leave(KErrNotReady);
				}

			//If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed on leave
			CMMSockSubSession::ReceivedL(ECNStop, TCFInternalEsock::TSubSess(ECNStop,Message()).CRef());
			break;

		case ECNWaitForIncoming:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNWaitForIncoming aMessage %08x"), this, &Message()) );
			//If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed on leave
			CMMSockSubSession::ReceivedL(ECNWaitForIncoming, TCFInternalEsock::TSubSess(ECNWaitForIncoming,Message()).CRef());
            break;

		case ECNCancelWaitForIncoming:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNCancelWaitForIncoming aMessage %08x"), this, &Message()) );
			CMMSockSubSession::ReceivedL(ECNWaitForIncoming, TEBase::TCancel().CRef());
			//CANCELATION - Do not call DontCompleteCurrentRequest() for the ECNCancelWaitForIncoming to be completed!
            break;

		case ECNProgressNotification:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNProgressNotification aMessage %08x"), this, &Message()) );
			CMMSockSubSession::ReceivedL(ECNProgressNotification, TCFInternalEsock::TSubSess(ECNProgressNotification,Message()).CRef()); //the ownership of the RMessage2 is taken by the activity
			break;

		case ECNCancelProgressNotification:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNCancelProgressNotification aMessage %08x"), this, &Message()) );
			CMMSockSubSession::ReceivedL(ECNProgressNotification, TEBase::TCancel().CRef());
			//CANCELATION - Do not call DontCompleteCurrentRequest() for the ECNCancelProgressNotification to be completed!
			break;

		case ECNIoctl:
		{
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNIoctl aMessage %08x"), this, &Message()) );
			RNodeInterface* sp = ServiceProvider();
			User::LeaveIfError(sp? KErrNone : KErrNotReady);

			CMMSockSubSession::ReceivedL(SafeMessage().Function(), TCprSendIoctl(SafeMessage()).CRef());
			DontCompleteCurrentRequest(); //TLegacyControlMessage will complete the message
		}
			break;

		case ECNCancelIoctl:
		{
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNCancelIoctl aMessage %08x"), this, &Message()) );
			RNodeInterface* sp = ServiceProvider();
			User::LeaveIfError(sp? KErrNone : KErrNotReady);

			CancelIoctl();
		}
			break;

#ifdef AVAILABILITY_READY
		case ECNEnumerateConnections:
			LOG(ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNEnumerateConnections aMessage %08x"), this, &Message()));
			CMMSockSubSession::ReceivedL(ECFActivityConnectionEnumerateConnections, TCFInternalEsock::TSubSess(ECNEnumerateConnections, Message()).CRef());
 			break;
#endif

		case ECNControl:
			ControlL();	//Decides how message gets completed
			break;

		case ECNProgress:
		    ProgressL();
			break;

		case ECNLastProgressError:
            LastProgressErrorL();
			break;

		case ECNGetOrSetParameters:
			GetOrSetParametersL();
			break;

		case ECNGetParametersResponseLength:
			GetParametersResponseL(ETrue);
			break;

		case ECNGetParametersResponse:
			GetParametersResponseL(EFalse);
			break;


		case ECNClose:
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tECNClose aMessage %08x"), this, &Message()) );
			SetClosing();
			//If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed on leave
			CMMSockSubSession::ReceivedL(ECNClose, TCFInternalEsock::TSubSess(ECNClose,Message()).CRef());
			break;

		case ESCPSStop:
            {
			LOG( ESockLog::Printf(KESockConnectionTag, _L8("CConnection %08x\tESCPSStop aMessage %08x"), this, &Message()) );

			// The filters match the legacy behaviour - subconnection has
			// to exist (implies Connection started).
			// Note: CNifAgentRef used to throw away the error returned
			// by the EMI compatibility layer hence we return KErrNone here.
		    TSubConnectionUniqueId subConnectionUniqueId = static_cast<TSubConnectionUniqueId>(Message().Int0());
		    if (ServiceProvider() &&
		        (ServiceProvider()->Type() & TCFClientType::EServProvider) &&
		        subConnectionUniqueId <= KNifEntireConnectionSubConnectionId+1)
    		    {
    			RNodeInterface* scpr = DefaultSubConnectionServiceProvider();

				if(scpr)
					{ // We can only start the 'stop' activity if we've got a service provider.
					RConnection::TConnStopType stopType = static_cast<RConnection::TConnStopType>(Message().Int1());

					// Validate the stop code.
					switch (stopType)
						{
					case RConnection::EStopNormal:
					case RConnection::EStopAuthoritative:
						break;

					default:
						User::Leave(KErrArgument);
						}

					// We start an activity to stop the subconnection and wait for it to send the TStopped response
					// message.  We cannot simply post the subconnection a message to stop because it causes the
					// response message to go stray as we would be performing an operation outside of an activity.
					// If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed
					// on leave.
					CMMSockSubSession::ReceivedL(
						ESCPSStop,
						TCFInternalEsock::TSubSess(
							ESCPSStop,
							Message()
							).CRef()
						);
					}
				else
					{ // Nothing to do
				    SetReturn(KErrNone);
					}
    		    }
    		else
        		{
    			User::Leave(KErrNotReady);
        		}
            }
			break;

		default:
			//iLegacyConnection must handle lifetimes of its own RMessage2s.
			iLegacyConnection.ProcessMessageL(Message());
			break;
		}
	}

void CConnection::GetReferenceL()
	{
	TName name;
	ComposeSubSessionName(this, name);
	Message().WriteL(0, name);
	}

_LIT_SECURITY_POLICY_C1(NifmanPolicyNetworkControl, ECapabilityNetworkControl);

/**
	Control method to send a general command towards the interface.
*/
void CConnection::ControlL()
	{
	TUint optionLevel = static_cast<TUint>(Message().Int0());
	TUint optionName  = static_cast<TUint>(Message().Int1());

	// Check that clients are not trying to use internal connection options
   	// make sure this doesn't colide with new control levels
	User::LeaveIfError((optionName & KConnInternalOptionBit)? KErrAccessDenied : KErrNone);

	switch(optionLevel)
		{
	case KCOLInterface:
		// This PlatSec check replaces that from Nifman's CNifSecureSession.
		if(!NifmanPolicyNetworkControl.CheckPolicy(Message()))
			{
			User::Leave(KErrPermissionDenied);
			}
		break;

	case KCOLConnection:
		switch(optionName)
			{
			case KCoEnableCloneOpen:
			case KCoDisableCloneOpen:
				SetCloneOpenPolicyL(optionName);
				break;

			default:
				iLegacyConnection.ControlL(optionName, optionLevel); //AConnectionLegacy decides when to complete message
				DontCompleteCurrentRequest(); //TLegacyControlMessage will complete the message
			}
		// KCOLConnection is all legacy stuff; no providers can/should help with it
		return;
		}

	TInt optionLength = SafeMessage().GetDesLengthL(2);
	if (optionName & (KConnReadUserDataBit | KConnWriteUserDataBit) && optionLength == 0)
		{
		User::Leave(KErrArgument); //No buffer for data
		}

	RNodeInterface* sp = ServiceProvider();
	User::LeaveIfError(sp? KErrNone : KErrNotReady);

	TLegacyControlMessage msg(SafeMessage());
	CMMSockSubSession::ReceivedL(SafeMessage().Function(), msg);
	DontCompleteCurrentRequest(); //TLegacyControlMessage will complete the message
	}


void CConnection::ProgressL()
    {
	if (iLastProgress.iStage != KConnectionUp && iLastProgress.iStage != KConnectionDown)
        {
		RNodeInterface* sp = ServiceProvider();
		User::LeaveIfError(sp? KErrNone : KErrNotReady);

		TCprRetrieveProgress msg(SafeMessage(), iLastProgress);
		CMMSockSubSession::ReceivedL(SafeMessage().Function(), msg);
        DontCompleteCurrentRequest(); //TCprRetrieveProgress will complete the message
        return;
        }

    TPckgBuf<TStateChange> progressBuf;
    progressBuf().iStage = iLastProgress.iStage;
    progressBuf().iError = iLastProgress.iError;

    Message().WriteL(0, progressBuf);
    SetReturn(KErrNone);
    }

void CConnection::LastProgressErrorL()
    {
    if (iLastProgress.iStage != KConnectionUp && iLastProgress.iStage != KConnectionDown)
        {
		RNodeInterface* sp = ServiceProvider();
		User::LeaveIfError(sp? KErrNone : KErrNotReady);

        TCprRetrieveLastProgressError msg(SafeMessage(), iLastProgressError);
		CMMSockSubSession::ReceivedL(SafeMessage().Function(), msg);
        DontCompleteCurrentRequest(); //TCprRetrieveLastProgressError will complete the message
        return;
        }

    TPckgBuf<TStateChange> progressBuf;
    progressBuf().iStage = iLastProgressError.iStage;
    progressBuf().iError = iLastProgressError.iError;
    ResetLastProgressError();

    Message().WriteL(0, progressBuf);
    SetReturn(KErrNone);
    }


void CConnection::GetOrSetParametersL()
    {
    if (ServiceProvider() == NULL)
        {
    	SetReturn(KErrNotReady);
    	return;
        }

    if (iCommsDataObject)
    	{
    	SetReturn(KErrInUse);
    	return;
    	}

	TInt cdoLength = Message().GetDesLengthL(0);
	RBuf8 cdoBuffer;
	cdoBuffer.CreateL(cdoLength);
	CleanupClosePushL(cdoBuffer);
	SafeMessage().ReadL(0, cdoBuffer);

   	TPtrC8 des(cdoBuffer);
   	iCommsDataObject = static_cast<XCommsDataObject*>(SMetaDataECom::LoadL(des));

	// Last minute sanity check
	if ((iCommsDataObject->OperationMode() == XCommsDataObject::EOperationGet
		&& !iCommsDataObject->IsGetSupported())
		|| (iCommsDataObject->OperationMode() == XCommsDataObject::EOperationSet
		&& !iCommsDataObject->IsSetSupported()))
		{
		CleanupStack::PopAndDestroy(); // cdoBuffer
		delete iCommsDataObject;
		iCommsDataObject = NULL;
		SetReturn(KErrCorrupt);
		return;
		}

   	// iCommsDataObject passed as *& and will be updated by the TGetOrSetParameters message
   	// upon error
	RNodeInterface* sp = ServiceProvider();
	if (sp == NULL)
		{
		delete iCommsDataObject;
		iCommsDataObject = NULL;
		SetReturn(KErrNotReady);
		return;
		}

	TGetOrSetParameters msg(SafeMessage(), iCommsDataObject);
	CMMSockSubSession::ReceivedL(SafeMessage().Function(), msg);
	DontCompleteCurrentRequest(); //TLegacyControlMessage will complete the message
	CleanupStack::PopAndDestroy(); // cdoBuffer
    }


void CConnection::GetParametersResponseL(TBool aReturnLength)
	{
    if (ServiceProvider() == NULL || !iCommsDataObject)
        {
    	SetReturn(KErrNotReady);
    	return;
        }

    if (aReturnLength)
    	{
    	// Client requesting required buffer length for the serialised object
    	iCommsDataObjectLength = iCommsDataObject->Length();
    	SetReturn(iCommsDataObjectLength);
    	}
    else
    	{
		RBuf8 cdoBuffer;
		cdoBuffer.CreateL(iCommsDataObjectLength);
		CleanupClosePushL(cdoBuffer);
		User::LeaveIfError(iCommsDataObject->Store(cdoBuffer));
		Message().WriteL(0, cdoBuffer);
		CleanupStack::PopAndDestroy();	// queryBundleBuffer

		delete iCommsDataObject;
		iCommsDataObject = NULL;
		iCommsDataObjectLength = 0;

		SetReturn(KErrNone);
    	}
	}

void CConnection::CancelIoctl()
	{
	const RPointerArray<CNodeActivityBase>& activities = Activities();
	for (TInt i = 0; i < activities.Count(); i++)
		{
		if (activities[i]->ActivitySigId() == ESock::ECFActivityConnectionLegacyRMessage2Handler)
			{
			ConnActivities::CConnLegacyRMessage2Activity* act = static_cast<ConnActivities::CConnLegacyRMessage2Activity*>(activities[i]);
			if (act->iSafeMessage.Function() == ECNIoctl)
				{
				act->SetCancelRequest(SafeMessage());
				CMMSockSubSession::ReceivedL(act->iSafeMessage.Function(), TEBase::TCancel().CRef());
				DontCompleteCurrentRequest();
				}
			}
		}
	}

void CConnection::SetCloneOpenPolicyL(TUint aOptionName)
	{
	const TInt policyParamIndex = 2;

	switch (aOptionName)
		{
		case KCoEnableCloneOpen:
			{
			// Enable the ability to perform a clone open towards this instance.  Read the
			// security policy passed in the option and store it in this instance.
			TSecurityPolicyBuf cloneOpenPolicy;
			SafeMessage().ReadL(policyParamIndex, cloneOpenPolicy);
			User::LeaveIfError(iCloneOpenPolicy.Set(cloneOpenPolicy));
			iCloneOpenEnabled = ETrue;
			break;
			}
		case KCoDisableCloneOpen:
			{
			// Disable the ability to perform a clone open towards this instance.
			iCloneOpenEnabled = EFalse;
			break;
			}
		}
	}

TInt CConnection::CheckCloneOpenPolicy(const RMessagePtr2& aMessage) const
	{
	if (iCloneOpenEnabled && iCloneOpenPolicy.CheckPolicy(aMessage))
		return KErrNone;
	else
		return KErrPermissionDenied;
	}


/**
@internalTechnology
*/
void CConnection::ReturnInterfacePtrL(MPlatsecApiExt*& aInterface)
    {
    aInterface = this;
    }

// AllInterfaceNotification

/**
	Legacy RConnection::AllInterfaceNotification implementation
*/
namespace AllInterfaceNotificationActivity
{
DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionAllInterfaceNotification, AllInterfaceNotification, TCFServiceProvider::TStart, CAllInterfaceNotificationActivity::NewL)
	NODEACTIVITY_ENTRY(KNoTag, TAddClient, TAwaitingStart, MeshMachine::TNoTag)
	// Find the tier manager and request notification from it.
	NODEACTIVITY_ENTRY(KNoTag, TFindTierManager, TAwaitingTierManager, MeshMachine::TNoTag)
	NODEACTIVITY_ENTRY(KNoTag, TJoinTierManager, TAwaitingJoinComplete, MeshMachine::TNoTag)

	// Start the notification activity and wait for notification
	NODEACTIVITY_ENTRY(KNoTag, TStartLinkNotification, TAwaitingLinkNotification, CoreStates::TCancelOrErrorOrTag<KNoTag>)

	// Enqueue the notification and wait for the next one - we loop here forever
	NODEACTIVITY_ENTRY(KNoTag, TEnqueueNotification, TAwaitingLinkNotification, CoreStates::TCancelOrErrorOrTag<KNoTag|EBackward>)

	THROUGH_TRIPLE_ENTRY(KErrorTag, MeshMachine::TStoreError, MeshMachine::TTag<KCancelTag>)
	// If we received a TCancel from CConnection, reply with TError to complete shutdown handshake. 
	THROUGH_NODEACTIVITY_ENTRY(KCancelTag, TSendErrorToConnection, MeshMachine::TTag<KCancelTag>)
	NODEACTIVITY_ENTRY(KCancelTag, TCancelLinkNotification, TAwaitingLinkNotificationError, MeshMachine::TNoTag)
	LAST_NODEACTIVITY_ENTRY(KNoTag, TLeaveTierManager) // no other sessions with tier so can safely fire & forget this
NODEACTIVITY_END()
}

namespace AllInterfaceNotificationActivities
{
DECLARE_DEFINE_ACTIVITY_MAP(allInterfaceNotificationActivities)
	ACTIVITY_MAP_ENTRY(AllInterfaceNotificationActivity, AllInterfaceNotification)
ACTIVITY_MAP_END()
}

CAllInterfaceNotificationWorker::CAllInterfaceNotificationWorker(ESock::CConnection& aConnection) :
	ACFMMNodeIdBase(AllInterfaceNotificationActivities::allInterfaceNotificationActivities::Self()),
	iConnection(aConnection)
	{
	LOG_NODE_CREATE(KESockConnectionTag, CAllInterfaceNotificationWorker);
	}

CAllInterfaceNotificationWorker::~CAllInterfaceNotificationWorker()
	{
	LOG_NODE_DESTROY(KESockConnectionTag, CAllInterfaceNotificationWorker);
	}

void CAllInterfaceNotificationWorker::Received(TNodeContextBase& aContext)
    {
	TNodeSignal::TMessageId noPeerIds[] = {
    	TCFServiceProvider::TStart::Id(),
    	TNodeSignal::TMessageId()	// list terminator
    	};
    MeshMachine::AMMNodeBase::Received(noPeerIds, aContext);
	MeshMachine::AMMNodeBase::PostReceived(aContext);
	}

void CAllInterfaceNotificationWorker::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
    {
	TNodeContext<CAllInterfaceNotificationWorker> ctx(*this, aMessage, aSender, aRecipient);
    CAllInterfaceNotificationWorker::Received(ctx);
    User::LeaveIfError(ctx.iReturn);
	}