commsfwutils/commsbufs/mbufgobblerlayer/src/mbufgobblerflow.cpp
branchRCL_3
changeset 76 576874e13a2c
equal deleted inserted replaced
73:5ebd530e523b 76:576874e13a2c
       
     1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Flow / Binder
       
    15 //  (data plane)
       
    16 //
       
    17 //
       
    18 //  This is a 3-plane comms layer implementation example, which has been customised to be a test layer which gobbles and releases ESOCK MBUFs.
       
    19 //  The MBuf gobbling functionality can be disabled by undefining the macro SYMBIAN_COMMSFW_MBUF_GOBBLER which is specified in mbufgobblerproviders.mmp.
       
    20 //  When SYMBIAN_COMMSFW_MBUF_GOBBLER is undefined, the source code specified by mbufgobblerproviders.mmp becomes a pass through layer i.e. it passes the data
       
    21 //  through to the layer above or below without altering it. This makes it useful as a starting point for implementing your own layers / providers;
       
    22 //  useful documentation on how to customise your own passthrough layer can be found in ..\docs\MbufGobblerLayer.doc
       
    23 //
       
    24 /**
       
    25  @file
       
    26  @internalComponent
       
    27 */
       
    28 
       
    29 #include <comms-infras/ss_activities.h>
       
    30 #include <comms-infras/ss_logext.h>
       
    31 #include <es_mbman.h>
       
    32 #include <mbufgobblerpubsub.h>
       
    33 #include "mbufgobblerflow.h"
       
    34 #include "mbufgobblerlog.h"
       
    35 
       
    36 // for panics
       
    37 _LIT(KPanicCategory, "MbufGobblerLayer");
       
    38 enum
       
    39 	{
       
    40 	KPanic_DestroyReceivedBeforeUnbind = 2001
       
    41 	};
       
    42 
       
    43 _LIT8(KNodeName, "CMbufGobblerFlow");
       
    44 
       
    45 
       
    46 ///////////////////////////
       
    47 // class CMbufGobblerFlow  //
       
    48 ///////////////////////////
       
    49 
       
    50 CMbufGobblerFlow* CMbufGobblerFlow::NewL(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf)
       
    51     {
       
    52     CMbufGobblerFlow* inst = new(ELeave) CMbufGobblerFlow(aFactory, aSubConnId, aProtocolIntf);
       
    53     CleanupStack::PushL(inst);
       
    54     inst->ConstructL();
       
    55     CleanupStack::Pop(inst);
       
    56     return inst;    
       
    57     }
       
    58     
       
    59 CMbufGobblerFlow::CMbufGobblerFlow(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf)
       
    60 /**
       
    61  * Constructor.
       
    62  *
       
    63  * @param aFactory Reference to the factory which created this object.
       
    64  * @param aTheLogger The logging object, ownership is passed to this object
       
    65  */
       
    66 	:ESock::CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf)
       
    67 	{
       
    68 	MBUFGOBBLER_LOG_NODE_CREATE(KMbufGobblerFlowSubTag, CMbufGobblerFlow, KNodeName, this->NodeId().Ptr());
       
    69 	}
       
    70 
       
    71 void CMbufGobblerFlow::ConstructL()
       
    72     {
       
    73 #ifdef SYMBIAN_COMMSFW_MBUF_GOBBLER
       
    74     iMBufGobbler = CMBufGobbler::NewL();
       
    75 #endif    
       
    76     }
       
    77     
       
    78 CMbufGobblerFlow::~CMbufGobblerFlow()
       
    79 	{
       
    80 	MBUFGOBBLER_LOG_NODE_DESTROY(KMbufGobblerFlowSubTag, CMbufGobblerFlow, KNodeName, this->NodeId().Ptr());
       
    81 	iBinders.ResetAndDestroy();
       
    82 #ifdef SYMBIAN_COMMSFW_MBUF_GOBBLER	
       
    83 	delete iMBufGobbler;
       
    84 #endif 
       
    85 	}
       
    86 
       
    87 
       
    88 
       
    89 ///////////////////////////////////////////
       
    90 // Methods from CSubConnectionFlowBase:  //
       
    91 ///////////////////////////////////////////
       
    92 
       
    93 ESock::MFlowBinderControl* CMbufGobblerFlow::DoGetBinderControlL()
       
    94 	{
       
    95 	return this;
       
    96 	}
       
    97 
       
    98 
       
    99 // Messages::ANode
       
   100 void CMbufGobblerFlow::ReceivedL(
       
   101 	const Messages::TRuntimeCtxId& aSender,
       
   102 	const Messages::TNodeId& aRecipient,
       
   103 	Messages::TSignatureBase& aMessage
       
   104 	)
       
   105 /**
       
   106 Method called on incoming SCPR messages
       
   107 
       
   108 @param aCFMessage message base
       
   109 */
       
   110     {
       
   111    
       
   112     LOGMESSAGE(KMbufGobblerFlowSubTag, KNodeName, this, aSender, aRecipient, aMessage);
       
   113     //LOG_NODE_INFO(KMbufGobblerFlowSubTag, KNodeName, *this); does not compile as flow inheritance is different to other nodes
       
   114     CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
       
   115 
       
   116 	// Dispatch the message locally
       
   117 	if (ESock::TCFDataClient::ERealmId == aMessage.MessageId().Realm())
       
   118 		{
       
   119 		switch (aMessage.MessageId().MessageId())
       
   120 			{
       
   121 
       
   122 			case ESock::TCFDataClient::TStart::EId :
       
   123 				{
       
   124 				iSubConnectionProvider.RNodeInterface::PostMessage(
       
   125 					Id(),
       
   126 					ESock::TCFDataClient::TStarted().CRef()
       
   127 					);
       
   128 				}
       
   129 				break;
       
   130 
       
   131 			case ESock::TCFDataClient::TStop::EId :
       
   132 				{
       
   133 				TInt i;
       
   134 				for (i=iBinders.Count()-1;i>=0;--i)
       
   135 					{
       
   136 				    CMbufGobblerBinder* binder = iBinders[i];
       
   137 				    binder->UnbindFromLowerFlow();
       
   138 					delete binder;
       
   139 					iBinders.Remove(i);
       
   140 					}
       
   141 				iSubConnectionProvider.PostMessage(Id(), ESock::TCFDataClient::TStopped(KErrNone).CRef());
       
   142 				}
       
   143 				break;
       
   144 
       
   145 			case ESock::TCFDataClient::TProvisionConfig::EId :
       
   146 				{
       
   147 				ESock::TCFDataClient::TProvisionConfig& aMess = Messages::message_cast<ESock::TCFDataClient::TProvisionConfig>(aMessage);
       
   148 				iAccessPointConfig.Close();
       
   149 				iAccessPointConfig.Open(aMess.iConfig);
       
   150 				}
       
   151 				break;
       
   152 
       
   153 			case ESock::TCFDataClient::TBindTo::EId :
       
   154 				{
       
   155 				ESock::TCFDataClient::TBindTo& bindToReq = Messages::message_cast<ESock::TCFDataClient::TBindTo>(aMessage);
       
   156 				if (bindToReq.iNodeId == Messages::TNodeId::NullId())
       
   157 					{
       
   158 					User::Leave(KErrNotSupported);
       
   159 					}
       
   160 
       
   161 				const Messages::TNodeId& commsId = bindToReq.iNodeId;
       
   162 				CSubConnectionFlowBase* lowerFlow = Messages::mnode_cast<CSubConnectionFlowBase>(&commsId.Node());
       
   163 
       
   164 				MFlowBinderControl* lowerBinderControl = lowerFlow->GetBinderControlL();
       
   165 				ASSERT(lowerBinderControl);
       
   166 
       
   167 				TInt i;
       
   168 				for (i=0;i<iBinders.Count();++i)
       
   169 					{
       
   170 					// binder for each protocol will request binder for same protocol from lower binder controller using this fn.
       
   171 					iBinders[i]->BindToLowerFlowL(*lowerBinderControl);
       
   172 					}
       
   173 				ASSERT(i); // there should be some binders!
       
   174 
       
   175 				Messages::RClientInterface::OpenPostMessageClose(
       
   176 					Id(),
       
   177 					aSender,
       
   178 					ESock::TCFDataClient::TBindToComplete().CRef()
       
   179 					);
       
   180 				}
       
   181 				break;
       
   182 
       
   183 			default:
       
   184 				ASSERT(EFalse);
       
   185 			}
       
   186 		}
       
   187 	else if (Messages::TEChild::ERealmId == aMessage.MessageId().Realm())
       
   188 		{
       
   189 		switch (aMessage.MessageId().MessageId())
       
   190 			{
       
   191 			case Messages::TEChild::TDestroy::EId :
       
   192 				{
       
   193 				TInt i;
       
   194 				for (i=0;i<iBinders.Count();++i)
       
   195 					{
       
   196 					// ensure all binders unbound
       
   197 					if (iBinders[i]->InUse())
       
   198 						{
       
   199 						//__CFLOG_0(KLogTag1, KLogTag2,_L("something is sending TDestroy to CMbufGobblerFlow before unbinding."));
       
   200 						User::Panic(KPanicCategory,KPanic_DestroyReceivedBeforeUnbind);
       
   201 						}
       
   202 						
       
   203 					// EXAMPLE CODE: cancel requests here if necessary...
       
   204 					//iBinders[i]->Cancel();
       
   205 					
       
   206 					}
       
   207 				if (i==iBinders.Count()) // all unbound
       
   208 					{
       
   209 					DeleteThisFlow();
       
   210 					}
       
   211 				}
       
   212 				break;
       
   213 
       
   214 			default:
       
   215 				ASSERT(EFalse);
       
   216 			}
       
   217 		}
       
   218 	// realm != TCFMessage::ERealmId
       
   219 	else
       
   220 		{
       
   221 		ASSERT(EFalse);
       
   222 		}
       
   223     }
       
   224 
       
   225 
       
   226 ///////////////////////////////////////
       
   227 // Methods from MFlowBinderControl:  //
       
   228 ///////////////////////////////////////
       
   229 
       
   230 ESock::MLowerControl* CMbufGobblerFlow::GetControlL(const TDesC8& aProtocol)
       
   231 /**
       
   232 Create and return an MLowerControl instance of the specified binder type.
       
   233 
       
   234 Called from upper layer during binding procedure.
       
   235 
       
   236 @param aProtocol Protocol type of the binder
       
   237 @return MLowerControl instance of the protocol type
       
   238 */
       
   239 	{
       
   240 	ESock::MLowerControl* lowerControl = FindOrCreateBinderL(aProtocol);
       
   241 	ASSERT(lowerControl);
       
   242 	return lowerControl;		
       
   243 	}
       
   244 
       
   245 
       
   246 ESock::MLowerDataSender* CMbufGobblerFlow::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
       
   247 	{
       
   248 	CMbufGobblerBinder* binder = FindOrCreateBinderL(aProtocol);
       
   249 	ASSERT(binder);
       
   250 	binder->BindToUpperL( *aReceiver, *aControl );
       
   251 
       
   252 	iSubConnectionProvider.RNodeInterface::PostMessage(
       
   253 		Id(),
       
   254 		ESock::TCFControlProvider::TActive().CRef()
       
   255 		);
       
   256 
       
   257 	return binder;
       
   258 	}
       
   259 
       
   260 void CMbufGobblerFlow::Unbind( ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
       
   261 	{
       
   262 	ASSERT(aReceiver);
       
   263 	ASSERT(aControl);
       
   264 	TInt i;
       
   265 	TInt numberUnbound=0;
       
   266 	for (i=0;i<iBinders.Count();++i)
       
   267 		{
       
   268 		numberUnbound += (iBinders[i]->UnbindFromUpper(*aReceiver,*aControl) ? 1 : 0);
       
   269 		}
       
   270 	ASSERT(i); // there should be some binders!
       
   271 	ASSERT(numberUnbound<=1); // only 1 unbind should have happened
       
   272 
       
   273 	iSubConnectionProvider.RNodeInterface::PostMessage(
       
   274 		Id(),
       
   275 		ESock::TCFControlProvider::TIdle().CRef()
       
   276 		);
       
   277 	}
       
   278 
       
   279 ESock::CSubConnectionFlowBase* CMbufGobblerFlow::Flow()
       
   280 	{
       
   281 	return this;
       
   282 	}
       
   283 
       
   284 
       
   285 /////////////////
       
   286 // Own methods //
       
   287 /////////////////
       
   288 
       
   289 CMbufGobblerBinder* CMbufGobblerFlow::FindOrCreateBinderL(const TDesC8& aProtocol)
       
   290 	{
       
   291 	
       
   292 	// EXAMPLE CODE, should you want your: perhaps your protocol to work with IPv4
       
   293 	//if (aProtocol.Compare(KIp4ProtocolName))
       
   294 	//	{  // only work with IPv4
       
   295 	//	User::Leave(KErrNotSupported);
       
   296 	//	}
       
   297 
       
   298 	for (TInt i=0;i<iBinders.Count();++i)
       
   299 		{
       
   300 		if(iBinders[i]->ProtocolName() == aProtocol)
       
   301 			{
       
   302 			return iBinders[i];
       
   303 			}
       
   304 		}
       
   305 	// not found.. create it.
       
   306 	CMbufGobblerBinder* newBinder = CMbufGobblerBinder::NewL(aProtocol);
       
   307 	CleanupStack::PushL(newBinder);
       
   308 	iBinders.AppendL(newBinder);
       
   309 	CleanupStack::Pop(newBinder);
       
   310 	return newBinder;
       
   311 	}
       
   312 	
       
   313     
       
   314 
       
   315 	
       
   316 
       
   317 //##################################################################################################
       
   318 	
       
   319 /////////////////////////////
       
   320 // class CMbufGobblerBinder  //
       
   321 /////////////////////////////
       
   322 
       
   323 
       
   324 ////////////////////
       
   325 // My constructor //
       
   326 ////////////////////
       
   327 
       
   328 CMbufGobblerBinder::CMbufGobblerBinder(const TDesC8& aProtocolName):
       
   329 	iLowerControl(NULL),
       
   330 	iLowerDataSender(NULL),
       
   331 	iUpperControl(NULL),
       
   332 	iUpperDataReceiver(NULL),
       
   333 	iProtocolName(aProtocolName)
       
   334 	{}
       
   335 
       
   336 CMbufGobblerBinder* CMbufGobblerBinder::NewL(const TDesC8& aProtocolName)
       
   337 	{
       
   338 	CMbufGobblerBinder* inst = new(ELeave) CMbufGobblerBinder(aProtocolName);
       
   339 	CleanupStack::PushL(inst);
       
   340 	inst->ConstructL();
       
   341 	CleanupStack::Pop(inst);
       
   342 	return inst;
       
   343 	}
       
   344 
       
   345 void CMbufGobblerBinder::ConstructL()
       
   346 	{
       
   347 	MBUFGOBBLER_TEST_DATA_INIT
       
   348 #if 0
       
   349 	// EXAMPLE CODE - set up everything you need to in this method.
       
   350 	//  Perhaps you have some kind of test control interface using pub/sub.. if so you'd do something like below..
       
   351 	//   Diff this file with networking/netperf/delaymeterproto/src/delaymeterflow.cpp for a full working implementation of such a control interface...
       
   352 	CActiveScheduler::Add(this);
       
   353 	DefinePubSubKeysL();
       
   354 	// watch for incoming commands
       
   355 	User::LeaveIfError(iProperty.Attach(TUid::Uid(KDelayMeterControlLevel), KCommandToDelayMeter));
       
   356 	iProperty.Subscribe(iStatus);
       
   357 	SetActive();
       
   358 #endif	
       
   359 	}
       
   360 
       
   361 /*virtual*/
       
   362 CMbufGobblerBinder::~CMbufGobblerBinder()
       
   363 	{
       
   364 	}
       
   365 
       
   366 
       
   367 
       
   368 ////////////////////////////////////////
       
   369 // Methods from ESock::MLowerControl: //
       
   370 ////////////////////////////////////////
       
   371 
       
   372 TInt CMbufGobblerBinder::GetName(TDes& aName)
       
   373 	{
       
   374 	TBuf16<10> tmp;
       
   375 	tmp.Copy(ProtocolName());
       
   376 	aName.Format(_L("mbufgobbler[%S][0x%08x]"), &tmp, this);
       
   377 	
       
   378 	return KErrNone;
       
   379 	}
       
   380 
       
   381 TInt CMbufGobblerBinder::BlockFlow(TBlockOption aOption)
       
   382 	{
       
   383 	if (iLowerControl==NULL)
       
   384 		{
       
   385 		return KErrNotReady;
       
   386 		}
       
   387 	return iLowerControl->BlockFlow(aOption) ;
       
   388 	}
       
   389 
       
   390 TInt CMbufGobblerBinder::GetConfig(TBinderConfig& aConfig)
       
   391 	{
       
   392 	if (iLowerControl==NULL)
       
   393 		{
       
   394 		return KErrNotReady;
       
   395 		}
       
   396 	return iLowerControl->GetConfig(aConfig) ;
       
   397 	}
       
   398 
       
   399 TInt CMbufGobblerBinder::Control(TUint aLevel, TUint aName, TDes8& aOption)
       
   400 	{
       
   401 	// Pass it on..
       
   402 	if (iLowerControl==NULL)
       
   403 		{
       
   404 		return KErrNotReady;
       
   405 		}
       
   406 	return iLowerControl->Control(aLevel,aName,aOption);
       
   407 	}
       
   408 	
       
   409 
       
   410 ///////////////////////////////////////////
       
   411 // Methods from ESock::MLowerDataSender: //
       
   412 ///////////////////////////////////////////
       
   413 
       
   414 ESock::MLowerDataSender::TSendResult CMbufGobblerBinder::Send(RMBufChain& aData)
       
   415 	{
       
   416 	// EXAMPLE NOTE:
       
   417 	//  This is where a protocol implementation will do its work on outgoing data.
       
   418 
       
   419     MBUFGOBBLER_TEST_POINT(KBinderSend,KErrNone)
       
   420 
       
   421 	if (iLowerControl==NULL)
       
   422 		{
       
   423 		return ESendBlocked; // returning this obliges us to send an unblock later..
       
   424 							 // so perhaps it'd be better to just swallow the packet?
       
   425 		}
       
   426 	return iLowerDataSender->Send(aData);
       
   427 	}
       
   428 
       
   429 ////////////////////////////////////////
       
   430 // Methods from ESock::MUpperControl: //
       
   431 ////////////////////////////////////////
       
   432 
       
   433 /*virtual*/
       
   434 void CMbufGobblerBinder::StartSending()
       
   435 	{
       
   436 	if (iUpperControl)
       
   437 		{
       
   438 		iUpperControl->StartSending();
       
   439 		}
       
   440 	else
       
   441 		{
       
   442 		ASSERT(1); // to allow setting a breakpoint
       
   443 		//__CFLOG_0(KLogTag1, KLogTag2,_L("CMbufGobblerBinder::StartSending: upper control not yet known!"));
       
   444 		}
       
   445 	}
       
   446 
       
   447 /*virtual*/
       
   448 void CMbufGobblerBinder::Error(TInt anError)
       
   449 	{
       
   450 	if (iUpperControl)
       
   451 		{
       
   452 		iUpperControl->Error(anError);
       
   453 		}
       
   454 	else
       
   455 		{
       
   456 		ASSERT(1); // to set a breakpoint
       
   457 		//__CFLOG_0(KLogTag1, KLogTag2,_L("CMbufGobblerBinder::Error: upper control not yet known!"));
       
   458 		}
       
   459 	}
       
   460 
       
   461 
       
   462 /////////////////////////////////////////////
       
   463 // Methods from ESock::MUpperDataReceiver: //
       
   464 /////////////////////////////////////////////
       
   465 
       
   466 /*virtual*/
       
   467 void CMbufGobblerBinder::Process(RMBufChain& aData)
       
   468 	{
       
   469 	// EXAMPLE NOTE:
       
   470 	//  This is where a protocol implementation will do its work on incoming data.
       
   471 
       
   472     MBUFGOBBLER_TEST_POINT(KBinderReceive,KErrNone)
       
   473 
       
   474 	if (iUpperDataReceiver == NULL)
       
   475 		{
       
   476 		// Why is the guy below still sending data to me when I'm not bound above?
       
   477 		//   Try to ignore it
       
   478 		ASSERT(1); // so a breakpoint can be set if necessary
       
   479 		//__CFLOG_0(KLogTag1, KLogTag2,_L("CMbufGobblerBinder::Process: incoming traffic discarded as upper data receiver not (or no longer) set"));
       
   480 		return;
       
   481 		}
       
   482 	iUpperDataReceiver->Process(aData);
       
   483 	}
       
   484 
       
   485 
       
   486 //////////////////////////
       
   487 // and my own methods.. //
       
   488 //////////////////////////
       
   489 
       
   490 // called by layer above calling my flow's BindL
       
   491 void CMbufGobblerBinder::BindToUpperL(MUpperDataReceiver& aUpperDataReceiver, MUpperControl& aUpperControl)
       
   492 	{
       
   493 	if(iUpperDataReceiver || iUpperControl) {User::Leave(KErrInUse);}
       
   494 	iUpperDataReceiver=&aUpperDataReceiver;
       
   495 	iUpperControl=&aUpperControl;
       
   496     MBUFGOBBLER_TEST_POINT(KBind,KErrNone)
       
   497 	}
       
   498 
       
   499 // called by layer above calling my flow's Unbind. Returns ETrue if unbind happened here, EFalse otherwise
       
   500 TBool CMbufGobblerBinder::UnbindFromUpper(MUpperDataReceiver& aUpperDataReceiver, MUpperControl& aUpperControl)
       
   501 	{
       
   502 	if(&aUpperDataReceiver == iUpperDataReceiver && &aUpperControl == iUpperControl)
       
   503 		{
       
   504 		iUpperDataReceiver=0;
       
   505 		iUpperControl=0;
       
   506 		return ETrue;
       
   507 		}
       
   508 	return EFalse;
       
   509 	}
       
   510 
       
   511 // called by my flow receiving a BinderRequest
       
   512 void CMbufGobblerBinder::BindToLowerFlowL(ESock::MFlowBinderControl& aLowerBinderControl)
       
   513 	{
       
   514 //	__CFLOG_0(KLogTag1, KLogTag2, _L("CMbufGobblerBinder::BindToLowerFlowL")); 
       
   515 	if(iLowerControl || iLowerDataSender)
       
   516 		{
       
   517 		User::Leave(KErrInUse);
       
   518 		}
       
   519 	
       
   520 	iBinderControl = &aLowerBinderControl;
       
   521 	iLowerControl = aLowerBinderControl.GetControlL(ProtocolName());
       
   522 	iLowerDataSender = aLowerBinderControl.BindL(ProtocolName(), this, this);
       
   523 	}
       
   524 
       
   525 void CMbufGobblerBinder::UnbindFromLowerFlow()
       
   526     {
       
   527     if (!iBinderControl)
       
   528         return;
       
   529     
       
   530     iBinderControl->Unbind(this, this);
       
   531     iBinderControl = NULL;
       
   532 
       
   533     iLowerControl = NULL;
       
   534     iLowerDataSender = NULL;
       
   535     }
       
   536 
       
   537 const TDesC8& CMbufGobblerBinder::ProtocolName() const
       
   538 	{
       
   539 	return iProtocolName;
       
   540 	}
       
   541 
       
   542 #ifdef SYMBIAN_COMMSFW_MBUF_GOBBLER 
       
   543 
       
   544 CMBufGobbler::CMBufGobbler():
       
   545     CActive(CActive::EPriorityStandard)
       
   546     {
       
   547     }   
       
   548     
       
   549 CMBufGobbler* CMBufGobbler::NewL()
       
   550     {
       
   551     CMBufGobbler* inst = new(ELeave) CMBufGobbler;
       
   552     CleanupStack::PushL(inst);
       
   553     inst->ConstructL();
       
   554     CleanupStack::Pop(inst);
       
   555     return inst;
       
   556     }
       
   557 
       
   558 void CMBufGobbler::ConstructL()
       
   559     {
       
   560     iChain.AllocL(128);
       
   561     
       
   562     CActiveScheduler::Add(this);
       
   563 
       
   564     TInt result = RProperty::Define(TUid::Uid(EMBufGobbler), EAdjustNumberOfMBufsRemainingInPool, RProperty::EInt);
       
   565     // Only want 1 instance of a MBufGobbler Layer, so just leave if KErrAlreadyExists returned
       
   566     User::LeaveIfError(result);
       
   567 
       
   568     // watch for incoming commands
       
   569     User::LeaveIfError(iProperty.Attach(TUid::Uid(EMBufGobbler), EAdjustNumberOfMBufsRemainingInPool));
       
   570 
       
   571     iProperty.Subscribe(iStatus);
       
   572     SetActive();
       
   573     }
       
   574 
       
   575 /*virtual*/ CMBufGobbler::~CMBufGobbler()
       
   576     {
       
   577     if (IsActive())
       
   578         {
       
   579         Cancel();   
       
   580         }
       
   581 
       
   582     iChain.Free();
       
   583     
       
   584     TInt result = RProperty::Delete(TUid::Uid(EMBufGobbler), EAdjustNumberOfMBufsRemainingInPool);  
       
   585     if (result != KErrNone)
       
   586         {
       
   587         RDebug::Print(_L("CMBufGobbler::~CMBufGobbler() %d"), result);
       
   588         }
       
   589     }
       
   590 
       
   591 /*virtual*/ void CMBufGobbler::DoCancel()
       
   592     {
       
   593     iProperty.Cancel();
       
   594     }
       
   595 
       
   596 /*virtual*/ void CMBufGobbler::RunL()
       
   597     {
       
   598     // Resubscribe to ensure that next pub/sub notification is picked up
       
   599     iProperty.Subscribe(iStatus);
       
   600     SetActive();
       
   601     
       
   602     TInt request=EGobbleAllMBufs;
       
   603     TInt pubSubRet = iProperty.Get(request);
       
   604     if (pubSubRet == KErrNone)
       
   605         {
       
   606         switch(request)
       
   607             {
       
   608             case EGobbleAllMBufs:
       
   609                 {
       
   610                 RMBufAllocator allocator;
       
   611                 RMBufChain chain;
       
   612                 TInt size = allocator.NextMBufSize(0);
       
   613                 while (size != KErrNotFound)
       
   614                     {
       
   615                     TInt ret = KErrNone;
       
   616                     while (ret == KErrNone)
       
   617                         {
       
   618                         ret = chain.Alloc(size);
       
   619                         if (ret==KErrNone )
       
   620                             {
       
   621                             iChain.Append(chain);
       
   622                             }
       
   623                         }
       
   624                     size = allocator.NextMBufSize(size);
       
   625                     }
       
   626                 TInt length = iChain.Length();
       
   627                 RDebug::Print(_L("Out of MBuf Memory... Total MBuf memory in use %d"), length);
       
   628                 TInt numBufs = iChain.NumBufs();
       
   629                 RDebug::Print(_L("Out of MBuf Memory... Total MBufs in use %d"), numBufs);
       
   630                 break;
       
   631                 }
       
   632             case EReleaseAllMBufs:
       
   633                 {
       
   634                 if(!iChain.IsEmpty())
       
   635                      {
       
   636                      iChain.Free();
       
   637                      ASSERT(!iChain.Length());
       
   638                     }
       
   639                 break;
       
   640                 }
       
   641             case EReleaseASingleMBuf:
       
   642                 {            
       
   643                 TInt length = iChain.Length();
       
   644                 if (length != 0)
       
   645                     {
       
   646                     TInt trimOffset = length - iChain.Last()->Size();
       
   647                     iChain.TrimEnd(trimOffset);
       
   648                     }
       
   649     
       
   650                 length = iChain.Length();
       
   651                 RDebug::Print(_L("MBufMemory De-Allocated... Total MBuf memory in use %d"), length);
       
   652                 break;
       
   653                 }
       
   654             default:
       
   655                 {
       
   656                 RDebug::Print(_L("CMBufGobbler::RunL(), invalid request %d"), request);
       
   657                 break;
       
   658                 }
       
   659             }
       
   660         }
       
   661     else
       
   662         {
       
   663         RDebug::Print(_L("Attempt to process MBufGobbler publish/subscribe failed with value for  %d"), pubSubRet);
       
   664         }
       
   665     }
       
   666 
       
   667 #endif