// Copyright (c) 2006-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:
// IPProto Connection Provider implementation
//
//
/**
@file
@internalComponent
*/
#include <comms-infras/ss_nodemessages.h>
#include <comms-infras/corecpractivities.h>
#include <comms-infras/ss_metaconnprov.h>
#include <comms-infras/sockmes.h> // for ioctl ipc
#include "IPProtoCprStates.h"
#include "IPProtoMessages.h"
#include "linkcprextensionapi.h"
#include <comms-infras/ss_datamonitoringprovider.h>
#include <comms-infras/ss_connlegacy.h>
#include <nifvar.h> // KLinkLayerOpen
#include <comms-infras/ss_nodemessages_internal.h>
#include <comms-infras/ss_legacyinterfaces.h>
#include <comms-infras/simpleselectorbase.h>
#include <commsdattypesv1_1_partner.h>
#include <es_prot_internal.h>
using namespace Messages;
using namespace MeshMachine;
using namespace IpProtoCpr;
using namespace ESock;
DEFINE_SMELEMENT(TStoreProvision, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TStoreProvision::DoL()
{
PRStates::TStoreProvision storeProvision(iContext);
storeProvision.DoL();
CIPProtoConnectionProvider& node = iContext.Node();
// Retrieve the idle timer values from the provisioning information bucket
const Meta::SMetaData* extension =
node.AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TIdleTimerValues::iUid, TIdleTimerValues::iId));
if (extension)
{
const TIdleTimerValues* vals = static_cast<const TIdleTimerValues*>(extension);
node.SetTimers(vals->iShortTimer, vals->iMediumTimer, vals->iLongTimer);
}
if (!node.iNodeLocalExtensionsCreated)
{
node.iNodeLocalExtensions.Open();
TPacketActivity* packetActivity = new(ELeave)TPacketActivity(&iContext.Node().iPeriodActivity);
CleanupStack::PushL(packetActivity);
node.iNodeLocalExtensions.AppendExtensionL(packetActivity);
CleanupStack::Pop(packetActivity);
// Allocate and add the data monitoring shared memory pointers to the provisioning info
TDataMonitoringConnProvisioningInfo* connProvisioningInfo = new (ELeave) TDataMonitoringConnProvisioningInfo(&node.iDataVolumes, &node.iThresholds);
CleanupStack::PushL(connProvisioningInfo);
node.iNodeLocalExtensions.AppendExtensionL(connProvisioningInfo);
CleanupStack::Pop(connProvisioningInfo);
// Allocate the data monitoring subconnection data structure.
//
// This used to be allocated in the SCPR, but it has been moved here to the CPR. This is because there can be
// temporary circumstances where there is more than one SCPR present - one or more of these in a leaving
// state and one in an active state. The access point config cannot presently hold provisioning information
// specific to an SCPR instance, so it is allocated and managed here in the CPR as a shared entity. Only
// one SCPR instance should be using this at a time, however.
TDataMonitoringSubConnProvisioningInfo* subConnProvisioningInfo = new (ELeave) TDataMonitoringSubConnProvisioningInfo(NULL, NULL);
CleanupStack::PushL(subConnProvisioningInfo);
node.iNodeLocalExtensions.AppendExtensionL(subConnProvisioningInfo);
CleanupStack::Pop(subConnProvisioningInfo);
// The CLinkCprExtensionApi may have been added previously if this is a reconnect scenario
// We add it again in this new override of the extensions, if the old container is fully superceded
// it will be closed and destroyed.
extension = CLinkCprExtensionApi::NewLC(iContext.Node());
node.iNodeLocalExtensions.AppendExtensionL(extension);
CleanupStack::Pop(); // CLinkCprExtensionApi
node.iNodeLocalExtensionsCreated = ETrue;
}
RMetaExtensionContainer mec;
mec.Open(iContext.Node().AccessPointConfig());
CleanupClosePushL(mec);
mec.AppendContainerL(node.iNodeLocalExtensions);
iContext.Node().iAccessPointConfig.Close();
iContext.Node().iAccessPointConfig.Open(mec);
CleanupStack::PopAndDestroy(&mec);
// For the case that this is an update of the provisioned info we forward it to non-leaving data clients
TClientIter<TDefaultClientMatchPolicy> iter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(
TClientType(TCFClientType::EData),
TClientType(0, TClientType::ELeaving)
);
for (TInt i = 0; iter[i]; i++)
{
iter[i]->PostMessage(
iContext.NodeId(),
TCFDataClient::TProvisionConfig(iContext.Node().iAccessPointConfig).CRef()
);
}
}
DEFINE_SMELEMENT(TAwaitingDataMonitoringNotification, NetStateMachine::MState, IpProtoCpr::TContext)
TBool TAwaitingDataMonitoringNotification::Accept()
{
return iContext.iMessage.IsMessage<TCFDataMonitoringNotification::TDataMonitoringNotification>();
}
DEFINE_SMELEMENT( TAwaitingGoneDown , NetStateMachine::MState, IpProtoCpr::TContext)
TBool TAwaitingGoneDown::Accept()
{
if (iContext.iMessage.IsMessage<TCFControlClient::TGoneDown>())
{
iContext.Node().LinkDown();
}
// return EFalse to allow further PRActivities processing
return EFalse;
}
DEFINE_SMELEMENT(TProcessDataMonitoringNotification, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TProcessDataMonitoringNotification::DoL()
{
TCFDataMonitoringNotification::TDataMonitoringNotification& msg =
message_cast<TCFDataMonitoringNotification::TDataMonitoringNotification>(iContext.iMessage);
iContext.Node().DataNotificationL(msg);
}
DEFINE_SMELEMENT(TAwaitingStart, NetStateMachine::MState, IpProtoCpr::TContext)
TBool TAwaitingStart::Accept()
{
CoreNetStates::TAwaitingStart state(iContext);
if (state.Accept())
{
iContext.Node().DisableTimers();
return ETrue;
}
return EFalse;
}
DEFINE_SMELEMENT(TCleanupStart, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TCleanupStart::DoL()
{
//Re-enable idle timers disabled by IpProtoCpr::TAwaitingStart
iContext.Node().EnableTimers();
}
DEFINE_SMELEMENT(TCheckIfLastControlClientLeaving, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TCheckIfLastControlClientLeaving::DoL()
{
CIPProtoConnectionProvider& node = iContext.Node();
node.ForceCheckShortTimerMode();
}
DEFINE_SMELEMENT(TAwaitingOpenCloseRoute, NetStateMachine::MState, IpProtoCpr::TContext)
TBool TAwaitingOpenCloseRoute::Accept()
{
return (iContext.iMessage.IsMessage<TCFIPProtoMessage::TOpenCloseRoute>());
}
DEFINE_SMELEMENT(TDoOpenCloseRoute, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TDoOpenCloseRoute::DoL()
{
TCFIPProtoMessage::TOpenCloseRoute& msg = message_cast<TCFIPProtoMessage::TOpenCloseRoute>(iContext.iMessage);
if (msg.iValue)
iContext.Node().OpenRoute();
else
iContext.Node().CloseRoute();
}
DEFINE_SMELEMENT(TLinkUp, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TLinkUp::DoL()
{
iContext.Node().LinkUp();
}
DEFINE_SMELEMENT(TLinkDown, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TLinkDown::DoL()
{
iContext.Node().LinkDown();
}
DEFINE_SMELEMENT(TStoreAndFilterDeprecatedAndForwardStateChange, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TStoreAndFilterDeprecatedAndForwardStateChange::DoL()
{
TCFMessage::TStateChange& msg = message_cast<TCFMessage::TStateChange>(iContext.iMessage);
//Forward to control clients if there are any
ESOCK_EXTLOG_VAR( (KESockConnectionTag, KIPProtoCprSubTag, _L8("CIPProtoConnectionProvider %x TStateChange\tProgress: %d, Error: %d"), &iContext.Node(), msg.iStateChange.iStage, msg.iStateChange.iError) );
//We are the only node accessing this CLinkCprExtensionApi interface so we can do it safely here.
//This is rather an exceptional situation, please keep the const_cast.
const CLinkCprExtensionApi* linkCPR = static_cast<const CLinkCprExtensionApi*>(iContext.Node().AccessPointConfig().FindExtension(CLinkCprExtensionApi::TypeId()));
const_cast<CLinkCprExtensionApi*>(linkCPR)->SetLastProgress(msg.iStateChange);
if ((KLinkLayerOpen != msg.iStateChange.iStage) && (KLinkLayerClosed != msg.iStateChange.iStage) )
{
//KLinkLayerOpen is now redundant with TCFControlClient::TGoneUp & TCFServiceProvider::TStarted
//KLinkLayerClosed is now redundant with TCFControlClient::TGoneDown & TCFServiceProvider::TStopped
//They have therefore been deprecated. Stack nodes are requested not to send the deprecated
//signals anymore. If stack nodes do send the deprecated signals, the signals will be eaten here
//because they confuse convergence and mobility layers, which may live just above.
TInt ctrlClientCount = iContext.Node().PostToClients<TDefaultClientMatchPolicy>(TNodeCtxId(iContext.ActivityId(), iContext.NodeId()), iContext.iMessage, TClientType(TCFClientType::ECtrl));
if (0==ctrlClientCount)
{ //If there are no control clients any more, forward to the control provider
iContext.Node().PostToClients<TDefaultClientMatchPolicy>(TNodeCtxId(iContext.ActivityId(), iContext.NodeId()), iContext.iMessage, TClientType(TCFClientType::ECtrlProvider));
}
}
}
DEFINE_SMELEMENT(TSendStopToSelf, NetStateMachine::MStateTransition, TContext)
void TSendStopToSelf::DoL()
{
iContext.iNodeActivity->PostRequestTo(iContext.NodeId(),
TCFServiceProvider::TStop(iContext.iNodeActivity->Error()).CRef());
}
DEFINE_SMELEMENT(TSendStarted, NetStateMachine::MStateTransition, TContext)
void TSendStarted::DoL()
{
//Set the idle timers
iContext.Node().EnableTimers();
iContext.Node().SetUsageProfile(KConnProfileMedium);
iContext.Node().SetTimerMode(CIPProtoConnectionProvider::ETimerMedium);
CoreNetStates::TSendStarted transition(iContext);
transition.DoL();
}
DEFINE_SMELEMENT(IpProtoCpr::TProcessDataClientStatusChange, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void IpProtoCpr::TProcessDataClientStatusChange::DoL()
{
TCFControlProvider::TDataClientStatusChange& msg = message_cast<TCFControlProvider::TDataClientStatusChange>(iContext.iMessage);
if(msg.iValue == TCFControlProvider::TDataClientStatusChange::EStarted)
{
iContext.iPeer->SetFlags(TCFClientType::EStarted);
}
else
{
iContext.iPeer->ClearFlags(TCFClientType::EStarted);
}
if(!msg.iValue && !iContext.Node().iSubConnEventDataSent)
{ // We're only interested in the provider being stopped.
ADataMonitoringProtocolReq* dmInterface = NULL;
iContext.Node().ReturnInterfacePtrL(dmInterface);
ADataMonitoringProvider* dmProvider = static_cast<ADataMonitoringProvider*>(dmInterface);
ASSERT(dmProvider); // Must always support this interface
TCFMessage::TSubConnDataTransferred wholeConnMsg(KNifEMCompatibilityLayerEntireSubConnectionUid, dmProvider->DataVolumesPtr()->iSentBytes, dmProvider->DataVolumesPtr()->iReceivedBytes);
TCFMessage::TSubConnDataTransferred defaultSubConnMsg(KNifEMCompatibilityLayerFakeSubConnectionId, dmProvider->DataVolumesPtr()->iSentBytes, dmProvider->DataVolumesPtr()->iReceivedBytes);
RNodeInterface* ctrlClient = iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::ECtrl));
if(ctrlClient)
{ // Can't send this if the client's gone
ctrlClient->PostMessage(iContext.NodeId(), wholeConnMsg);
ctrlClient->PostMessage(iContext.NodeId(), defaultSubConnMsg);
iContext.Node().iSubConnEventDataSent = ETrue;
}
}
}
DEFINE_SMELEMENT(TAwaitingIoctlMessage, NetStateMachine::MState, IpProtoCpr::TContext)
TBool TAwaitingIoctlMessage::Accept()
{
if (iContext.iMessage.IsTypeOf(Meta::STypeId::CreateSTypeId(TCFSigLegacyRMessage2Ext::EUid, TCFSigLegacyRMessage2Ext::ETypeId)))
{
TCFSigLegacyRMessage2Ext& msg = static_cast<TCFSigLegacyRMessage2Ext&>(iContext.iMessage);
if (msg.iMessage.Function() == ECNIoctl)
{
return ETrue;
}
}
return EFalse;
}
DEFINE_SMELEMENT(TForwardToDefaultDataClient, NetStateMachine::MStateTransition, IpProtoCpr::TContext)
void TForwardToDefaultDataClient::DoL()
{
ASSERT(iContext.iMessage.IsTypeOf(Meta::STypeId::CreateSTypeId(TCFSigLegacyRMessage2Ext::EUid, TCFSigLegacyRMessage2Ext::ETypeId)));
RNodeInterface* dc = iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData));
iContext.Activity()->PostRequestTo(*dc, iContext.iMessage);
}