diff -r 9200f38b1324 -r 042fd2753b8f telephonyprotocols/pdplayer/umts/test/mbufgobblerlayer/src/mbufgobblerflow.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/telephonyprotocols/pdplayer/umts/test/mbufgobblerlayer/src/mbufgobblerflow.cpp Wed Oct 13 15:51:46 2010 +0300 @@ -0,0 +1,659 @@ +// Copyright (c) 2010 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: +// Flow / Binder +// (data plane) +// + +/** + @file + @internalComponent +*/ + +#include +#include +#include +#include +#include "mbufgobblerflow.h" +#include "mbufgobblerlog.h" + +// for panics +_LIT(KPanicCategory, "MbufGobblerLayer"); +enum + { + KPanic_DestroyReceivedBeforeUnbind = 2001 + }; + +_LIT8(KNodeName, "CMbufGobblerFlow"); + + +/////////////////////////// +// class CMbufGobblerFlow // +/////////////////////////// + +CMbufGobblerFlow* CMbufGobblerFlow::NewL(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf) + { + CMbufGobblerFlow* inst = new(ELeave) CMbufGobblerFlow(aFactory, aSubConnId, aProtocolIntf); + CleanupStack::PushL(inst); + inst->ConstructL(); + CleanupStack::Pop(inst); + return inst; + } + +CMbufGobblerFlow::CMbufGobblerFlow(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf) +/** + * Constructor. + * + * @param aFactory Reference to the factory which created this object. + * @param aTheLogger The logging object, ownership is passed to this object + */ + :ESock::CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf) + { + MBUFGOBBLER_LOG_NODE_CREATE(KMbufGobblerFlowSubTag, CMbufGobblerFlow, KNodeName, this->NodeId().Ptr()); + } + +void CMbufGobblerFlow::ConstructL() + { + iPassThroughMBufGobbler = CMBufGobbler::NewL(); + } + +CMbufGobblerFlow::~CMbufGobblerFlow() + { + MBUFGOBBLER_LOG_NODE_DESTROY(KMbufGobblerFlowSubTag, CMbufGobblerFlow, KNodeName, this->NodeId().Ptr()); + iBinders.ResetAndDestroy(); + delete iPassThroughMBufGobbler; + } + + + +/////////////////////////////////////////// +// Methods from CSubConnectionFlowBase: // +/////////////////////////////////////////// + +ESock::MFlowBinderControl* CMbufGobblerFlow::DoGetBinderControlL() + { + return this; + } + + +// Messages::ANode +void CMbufGobblerFlow::ReceivedL( + const Messages::TRuntimeCtxId& aSender, + const Messages::TNodeId& aRecipient, + Messages::TSignatureBase& aMessage + ) +/** +Method called on incoming SCPR messages + +@param aCFMessage message base +*/ + { + + LOGMESSAGE(KMbufGobblerFlowSubTag, KNodeName, this, aSender, aRecipient, aMessage); + //LOG_NODE_INFO(KMbufGobblerFlowSubTag, KNodeName, *this); does not compile as flow inheritance is different to other nodes + CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage); + + // Dispatch the message locally + if (ESock::TCFDataClient::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + + case ESock::TCFDataClient::TStart::EId : + { + iSubConnectionProvider.RNodeInterface::PostMessage( + Id(), + ESock::TCFDataClient::TStarted().CRef() + ); + } + break; + + case ESock::TCFDataClient::TStop::EId : + { + TInt i; + for (i=iBinders.Count()-1;i>=0;--i) + { + CMbufGobblerBinder* mbufGobblerBinder = iBinders[i]; + mbufGobblerBinder->UnbindFromLowerFlow(); + delete mbufGobblerBinder; + iBinders.Remove(i); + } + iSubConnectionProvider.PostMessage(Id(), ESock::TCFDataClient::TStopped(KErrNone).CRef()); + } + break; + + case ESock::TCFDataClient::TProvisionConfig::EId : + { + ESock::TCFDataClient::TProvisionConfig& aMess = Messages::message_cast(aMessage); + iAccessPointConfig.Close(); + iAccessPointConfig.Open(aMess.iConfig); + } + break; + + case ESock::TCFDataClient::TBindTo::EId : + { + ESock::TCFDataClient::TBindTo& bindToReq = Messages::message_cast(aMessage); + if (bindToReq.iNodeId == Messages::TNodeId::NullId()) + { + User::Leave(KErrNotSupported); + } + + const Messages::TNodeId& commsId = bindToReq.iNodeId; + CSubConnectionFlowBase* lowerFlow = Messages::mnode_cast(&commsId.Node()); + + MFlowBinderControl* lowerBinderControl = lowerFlow->GetBinderControlL(); + ASSERT(lowerBinderControl); + + TInt i; + for (i=0;iBindToLowerFlowL(*lowerBinderControl); + } + ASSERT(i); // there should be some binders! + + Messages::RClientInterface::OpenPostMessageClose( + Id(), + aSender, + ESock::TCFDataClient::TBindToComplete().CRef() + ); + } + break; + + default: + ASSERT(EFalse); + } + } + else if (Messages::TEChild::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + case Messages::TEChild::TDestroy::EId : + { + TInt i; + for (i=0;iInUse()) + { + //__CFLOG_0(KLogTag1, KLogTag2,_L("something is sending TDestroy to CMbufGobblerFlow before unbinding.")); + User::Panic(KPanicCategory,KPanic_DestroyReceivedBeforeUnbind); + } + + // EXAMPLE CODE: cancel requests here if necessary... + //iBinders[i]->Cancel(); + + } + if (i==iBinders.Count()) // all unbound + { + DeleteThisFlow(); + } + } + break; + + default: + ASSERT(EFalse); + } + } + // realm != TCFMessage::ERealmId + else + { + ASSERT(EFalse); + } + } + + +/////////////////////////////////////// +// Methods from MFlowBinderControl: // +/////////////////////////////////////// + +ESock::MLowerControl* CMbufGobblerFlow::GetControlL(const TDesC8& aProtocol) +/** +Create and return an MLowerControl instance of the specified binder type. + +Called from upper layer during binding procedure. + +@param aProtocol Protocol type of the binder +@return MLowerControl instance of the protocol type +*/ + { + ESock::MLowerControl* lowerControl = FindOrCreateBinderL(aProtocol); + ASSERT(lowerControl); + return lowerControl; + } + + +ESock::MLowerDataSender* CMbufGobblerFlow::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) + { + CMbufGobblerBinder* binder = FindOrCreateBinderL(aProtocol); + ASSERT(binder); + binder->BindToUpperL( *aReceiver, *aControl ); + + iSubConnectionProvider.RNodeInterface::PostMessage( + Id(), + ESock::TCFControlProvider::TActive().CRef() + ); + + return binder; + } + +void CMbufGobblerFlow::Unbind( ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) + { + ASSERT(aReceiver); + ASSERT(aControl); + TInt i; + TInt numberUnbound=0; + for (i=0;iUnbindFromUpper(*aReceiver,*aControl) ? 1 : 0); + } + ASSERT(i); // there should be some binders! + ASSERT(numberUnbound<=1); // only 1 unbind should have happened + + iSubConnectionProvider.RNodeInterface::PostMessage( + Id(), + ESock::TCFControlProvider::TIdle().CRef() + ); + } + +ESock::CSubConnectionFlowBase* CMbufGobblerFlow::Flow() + { + return this; + } + + +///////////////// +// Own methods // +///////////////// + +CMbufGobblerBinder* CMbufGobblerFlow::FindOrCreateBinderL(const TDesC8& aProtocol) + { + + // EXAMPLE CODE: perhaps you only want this protocol to work with IPv4 + //if (aProtocol.Compare(KIp4ProtocolName)) + // { // only work with IPv4 + // User::Leave(KErrNotSupported); + // } + + for (TInt i=0;iProtocolName() == aProtocol) + { + return iBinders[i]; + } + } + // not found.. create it. + CMbufGobblerBinder* newBinder = CMbufGobblerBinder::NewL(aProtocol); + CleanupStack::PushL(newBinder); + iBinders.AppendL(newBinder); + CleanupStack::Pop(newBinder); + return newBinder; + } + + + + + +//################################################################################################## + +///////////////////////////// +// class CMbufGobblerBinder // +///////////////////////////// + + +//////////////////// +// My constructor // +//////////////////// + +CMbufGobblerBinder::CMbufGobblerBinder(const TDesC8& aProtocolName): + iLowerControl(NULL), + iLowerDataSender(NULL), + iUpperControl(NULL), + iUpperDataReceiver(NULL), + iProtocolName(aProtocolName) + {} + +CMbufGobblerBinder* CMbufGobblerBinder::NewL(const TDesC8& aProtocolName) + { + CMbufGobblerBinder* inst = new(ELeave) CMbufGobblerBinder(aProtocolName); + CleanupStack::PushL(inst); + inst->ConstructL(); + CleanupStack::Pop(inst); + return inst; + } + +void CMbufGobblerBinder::ConstructL() + { + MBUFGOBBLER_TEST_DATA_INIT +#if 0 + // EXAMPLE CODE - set up everything you need to in this method. + // Perhaps you have some kind of test control interface using pub/sub.. if so you'd do something like below.. + // Diff this file with networking/netperf/delaymeterproto/src/delaymeterflow.cpp for a full working implementation of such a control interface... + CActiveScheduler::Add(this); + DefinePubSubKeysL(); + // watch for incoming commands + User::LeaveIfError(iProperty.Attach(TUid::Uid(KDelayMeterControlLevel), KCommandToDelayMeter)); + iProperty.Subscribe(iStatus); + SetActive(); +#endif + } + +/*virtual*/ +CMbufGobblerBinder::~CMbufGobblerBinder() + { + } + + + +//////////////////////////////////////// +// Methods from ESock::MLowerControl: // +//////////////////////////////////////// + +TInt CMbufGobblerBinder::GetName(TDes& aName) + { + TBuf16<10> tmp; + tmp.Copy(ProtocolName()); + aName.Format(_L("mbufgobbler[%S][0x%08x]"), &tmp, this); + + return KErrNone; + } + +TInt CMbufGobblerBinder::BlockFlow(TBlockOption aOption) + { + if (iLowerControl==NULL) + { + return KErrNotReady; + } + return iLowerControl->BlockFlow(aOption) ; + } + +TInt CMbufGobblerBinder::GetConfig(TBinderConfig& aConfig) + { + if (iLowerControl==NULL) + { + return KErrNotReady; + } + return iLowerControl->GetConfig(aConfig) ; + } + +TInt CMbufGobblerBinder::Control(TUint aLevel, TUint aName, TDes8& aOption) + { + // Pass it on.. + if (iLowerControl==NULL) + { + return KErrNotReady; + } + return iLowerControl->Control(aLevel,aName,aOption); + } + + +/////////////////////////////////////////// +// Methods from ESock::MLowerDataSender: // +/////////////////////////////////////////// + +ESock::MLowerDataSender::TSendResult CMbufGobblerBinder::Send(RMBufChain& aData) + { + // EXAMPLE NOTE: + // This is where your protocol will do its work on outgoing data. + + MBUFGOBBLER_TEST_POINT(KBinderSend,KErrNone) + + if (iLowerControl==NULL) + { + return ESendBlocked; // returning this obliges us to send an unblock later.. + // so perhaps it'd be better to just swallow the packet? + } + return iLowerDataSender->Send(aData); + } + + +//////////////////////////////////////// +// Methods from ESock::MUpperControl: // +//////////////////////////////////////// + +/*virtual*/ +void CMbufGobblerBinder::StartSending() + { + if (iUpperControl) + { + iUpperControl->StartSending(); + } + else + { + ASSERT(1); // to allow setting a breakpoint + //__CFLOG_0(KLogTag1, KLogTag2,_L("CMbufGobblerBinder::StartSending: upper control not yet known!")); + } + } + +/*virtual*/ +void CMbufGobblerBinder::Error(TInt anError) + { + if (iUpperControl) + { + iUpperControl->Error(anError); + } + else + { + ASSERT(1); // to set a breakpoint + //__CFLOG_0(KLogTag1, KLogTag2,_L("CMbufGobblerBinder::Error: upper control not yet known!")); + } + } + + +///////////////////////////////////////////// +// Methods from ESock::MUpperDataReceiver: // +///////////////////////////////////////////// + +/*virtual*/ +void CMbufGobblerBinder::Process(RMBufChain& aData) + { + // EXAMPLE NOTE: + // This is where your protocol will do its work on incoming data. + + MBUFGOBBLER_TEST_POINT(KBinderReceive,KErrNone) + + if (iUpperDataReceiver == NULL) + { + // Why is the guy below still sending data to me when I'm not bound above? + // Try to ignore it + ASSERT(1); // so a breakpoint can be set if necessary + //__CFLOG_0(KLogTag1, KLogTag2,_L("CMbufGobblerBinder::Process: incoming traffic discarded as upper data receiver not (or no longer) set")); + return; + } + iUpperDataReceiver->Process(aData); + } + + +////////////////////////// +// and my own methods.. // +////////////////////////// + +// called by layer above calling my flow's BindL +void CMbufGobblerBinder::BindToUpperL(MUpperDataReceiver& aUpperDataReceiver, MUpperControl& aUpperControl) + { + if(iUpperDataReceiver || iUpperControl) {User::Leave(KErrInUse);} + iUpperDataReceiver=&aUpperDataReceiver; + iUpperControl=&aUpperControl; + MBUFGOBBLER_TEST_POINT(KBind,KErrNone) + } + +// called by layer above calling my flow's Unbind. Returns ETrue if unbind happened here, EFalse otherwise +TBool CMbufGobblerBinder::UnbindFromUpper(MUpperDataReceiver& aUpperDataReceiver, MUpperControl& aUpperControl) + { + if(&aUpperDataReceiver == iUpperDataReceiver && &aUpperControl == iUpperControl) + { + iUpperDataReceiver=0; + iUpperControl=0; + return ETrue; + } + return EFalse; + } + +// called by my flow receiving a BinderRequest +void CMbufGobblerBinder::BindToLowerFlowL(ESock::MFlowBinderControl& aLowerBinderControl) + { +// __CFLOG_0(KLogTag1, KLogTag2, _L("CMbufGobblerBinder::BindToLowerFlowL")); + if(iLowerControl || iLowerDataSender) + { + User::Leave(KErrInUse); + } + + iBinderControl = &aLowerBinderControl; + iLowerControl = aLowerBinderControl.GetControlL(ProtocolName()); + iLowerDataSender = aLowerBinderControl.BindL(ProtocolName(), this, this); + } + +void CMbufGobblerBinder::UnbindFromLowerFlow() + { + if (!iBinderControl) + return; + + iBinderControl->Unbind(this, this); + iBinderControl = NULL; + + iLowerControl = NULL; + iLowerDataSender = NULL; + } + +const TDesC8& CMbufGobblerBinder::ProtocolName() const + { + return iProtocolName; + } + +CMBufGobbler::CMBufGobbler(): + CActive(CActive::EPriorityStandard) + { + } + +CMBufGobbler* CMBufGobbler::NewL() + { + CMBufGobbler* inst = new(ELeave) CMBufGobbler; + CleanupStack::PushL(inst); + inst->ConstructL(); + CleanupStack::Pop(inst); + return inst; + } + +void CMBufGobbler::ConstructL() + { + iChain.AllocL(128); + + CActiveScheduler::Add(this); + + TInt result = RProperty::Define(TUid::Uid(EMBufGobbler), EAdjustNumberOfMBufsRemainingInPool, RProperty::EInt); + // Only want 1 instance of a MBufGobbler Layer, so just leave if KErrAlreadyExists returned + User::LeaveIfError(result); + + // watch for incoming commands + User::LeaveIfError(iProperty.Attach(TUid::Uid(EMBufGobbler), EAdjustNumberOfMBufsRemainingInPool)); + + iProperty.Subscribe(iStatus); + SetActive(); + } + +/*virtual*/ CMBufGobbler::~CMBufGobbler() + { + if (IsActive()) + { + Cancel(); + } + + iChain.Free(); + + TInt result = RProperty::Delete(TUid::Uid(EMBufGobbler), EAdjustNumberOfMBufsRemainingInPool); + if (result != KErrNone) + { + RDebug::Print(_L("CMBufGobbler::~CMBufGobbler() %d"), result); + } + } + +/*virtual*/ void CMBufGobbler::DoCancel() + { + iProperty.Cancel(); + } + +/*virtual*/ void CMBufGobbler::RunL() + { + // Resubscribe to ensure that next pub/sub notification is picked up + iProperty.Subscribe(iStatus); + SetActive(); + + TInt request=EGobbleAllMBufs; + TInt pubSubRet = iProperty.Get(request); + if (pubSubRet == KErrNone) + { + switch(request) + { + case EGobbleAllMBufs: + { + RMBufAllocator allocator; + RMBufChain chain; + TInt size = allocator.NextMBufSize(0); + while (size != KErrNotFound) + { + TInt ret = KErrNone; + while (ret == KErrNone) + { + ret = chain.Alloc(size); + if (ret==KErrNone ) + { + iChain.Append(chain); + } + } + size = allocator.NextMBufSize(size); + } + TInt length = iChain.Length(); + RDebug::Print(_L("Out of MBuf Memory... Total MBuf memory in use %d"), length); + TInt numBufs = iChain.NumBufs(); + RDebug::Print(_L("Out of MBuf Memory... Total MBufs in use %d"), numBufs); + break; + } + case EReleaseAllMBufs: + { + if(!iChain.IsEmpty()) + { + iChain.Free(); + ASSERT(!iChain.Length()); + } + break; + } + case EReleaseASingleMBuf: + { + TInt length = iChain.Length(); + if (length != 0) + { + TInt trimOffset = length - iChain.Last()->Size(); + iChain.TrimEnd(trimOffset); + } + + length = iChain.Length(); + RDebug::Print(_L("MBufMemory De-Allocated... Total MBuf memory in use %d"), length); + break; + } + default: + { + RDebug::Print(_L("CMBufGobbler::RunL(), invalid request %d"), request); + break; + } + } + } + else + { + RDebug::Print(_L("Attempt to process MBufGobbler publish/subscribe failed with value for %d"), pubSubRet); + } + } + + + + +