networkingtestandutils/networkingperformancemeasurementtools/delaymeterproto/src/delaymeterflow.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkingtestandutils/networkingperformancemeasurementtools/delaymeterproto/src/delaymeterflow.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,804 @@
+// Copyright (c) 2008-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:
+// Protocol used by netperfte to insert timestamps on incoming packets,
+// and record delays of outgoing packets which it reports back to netperfte
+// 
+//
+
+/**
+ @file
+ @internalTechnology
+*/
+
+#include "e32base.h"
+#include "delaymeterflow.h"
+#include "delaymeterprotofactory.h"
+#include <comms-infras/ss_activities.h>
+#ifdef SYMBIAN_OLD_EXPORT_LOCATION
+#include <networking/delaymeter.h>
+#include <networking/netperftrace.h>
+#else
+#include "netperftrace.h"
+#include "delaymeter.h"
+#endif
+#include <comms-infras/ss_logext.h>
+#include <es_mbman.h>
+
+#ifdef _DEBUG
+_LIT8(KNifSubDirTest, "DelayMeter");
+#endif
+
+// for panics
+_LIT(KPanicCategory, "DelayMeterProtocol");
+enum
+	{
+	KPanic_DestroyReceivedBeforeUnbind = 2001
+	};
+
+
+_LIT8(KIp4ProtocolName, "ip");
+
+
+using namespace ESock;
+using namespace DelayMeter;
+
+//
+// class CDelayMeterFlow  //
+//
+
+
+CDelayMeterFlow::CDelayMeterFlow(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)
+	{
+	LOG_NODE_CREATE(KNifSubDirTest, CDelayMeterFlow);
+	}
+
+CDelayMeterFlow::~CDelayMeterFlow()
+	{
+	iBinders.ResetAndDestroy();
+	}
+
+
+
+//
+// Methods from CSubConnectionFlowBase:  //
+//
+
+ESock::MFlowBinderControl* CDelayMeterFlow::DoGetBinderControlL()
+	{
+	return this;
+	}
+
+// Messages::ANode
+void CDelayMeterFlow::ReceivedL(
+	const Messages::TRuntimeCtxId& aSender,
+	const Messages::TNodeId& aRecipient,
+	Messages::TSignatureBase& aMessage
+	)
+/**
+Method called on incoming SCPR messages
+
+@param aSender Sending Node
+@param aMessage message base
+@param aMessage The message
+*/
+    {
+    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)
+					{
+					delete iBinders[i];
+					iBinders.Remove(i);
+					}
+				iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStopped(KErrNone).CRef());
+				}
+				break;
+
+			case ESock::TCFDataClient::TProvisionConfig::EId :
+				{
+				ESock::TCFDataClient::TProvisionConfig& aMess = Messages::message_cast<ESock::TCFDataClient::TProvisionConfig>(aMessage);
+				iAccessPointConfig.Close();
+				iAccessPointConfig.Open(aMess.iConfig);
+				}
+				break;
+
+			case ESock::TCFDataClient::TBindTo::EId :
+				{
+				ESock::TCFDataClient::TBindTo& bindToReq = Messages::message_cast<ESock::TCFDataClient::TBindTo>(aMessage);
+				if (bindToReq.iNodeId == Messages::TNodeId::NullId())
+					{
+					User::Leave(KErrNotSupported);
+					}
+
+				const Messages::TNodeId& commsId = bindToReq.iNodeId;
+				CSubConnectionFlowBase* lowerFlow = Messages::mnode_cast<CSubConnectionFlowBase>(&commsId.Node());
+
+				MFlowBinderControl* lowerBinderControl = lowerFlow->GetBinderControlL();
+				ASSERT(lowerBinderControl);
+
+				TInt i;
+				for (i=0;i<iBinders.Count();++i)
+					{
+					// binder for each protocol will request binder for same protocol from lower binder controller using this fn.
+					iBinders[i]->BindToLowerFlowL(*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;i<iBinders.Count();++i)
+					{
+					// ensure all binders unbound
+					if (iBinders[i]->InUse())
+						{
+						// WHO IS CALLING DESTROY ON ME BEFORE UNBINDING? They need a punch.
+						NETPERF_TRACE_1(_L("something is sending TDestroy to CDelayMeterFlow 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* CDelayMeterFlow::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* CDelayMeterFlow::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
+	{
+	CDelayMeterBinder* binder = FindOrCreateBinderL(aProtocol);
+	ASSERT(binder);
+	binder->BindToUpperL( *aReceiver, *aControl );
+
+	iSubConnectionProvider.RNodeInterface::PostMessage(
+		Id(),
+		TCFControlProvider::TActive().CRef()
+		);
+
+	return binder;
+	}
+
+void CDelayMeterFlow::Unbind( ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
+	{
+	ASSERT(aReceiver);
+	ASSERT(aControl);
+	TInt i;
+	TInt numberUnbound=0;
+	for (i=0;i<iBinders.Count();++i)
+		{
+		numberUnbound += (iBinders[i]->UnbindFromUpper(*aReceiver,*aControl) ? 1 : 0);
+		}
+	ASSERT(i); // there should be some binders!
+	ASSERT(numberUnbound<=1); // only 1 unbind should have happened
+
+	iSubConnectionProvider.RNodeInterface::PostMessage(
+		Id(),
+		TCFControlProvider::TIdle().CRef()
+		);
+	}
+
+ESock::CSubConnectionFlowBase* CDelayMeterFlow::Flow()
+	{
+	return this;
+	}
+
+
+//
+// Own methods //
+//
+
+CDelayMeterBinder* CDelayMeterFlow::FindOrCreateBinderL(const TDesC8& aProtocol)
+	{
+	if (aProtocol.Compare(KIp4ProtocolName))
+		{  // only work with IPv4
+		User::Leave(KErrNotSupported);
+		}
+
+	for (TInt i=0;i<iBinders.Count();++i)
+		{
+		if (iBinders[i]->ProtocolName() == aProtocol)
+			{
+			return iBinders[i];
+			}
+		}
+	// not found.. create it.
+	CDelayMeterBinder* newBinder = CDelayMeterBinder::NewL();
+	CleanupStack::PushL(newBinder);
+	iBinders.AppendL(newBinder);
+	CleanupStack::Pop(newBinder);
+	return newBinder;
+	}
+
+
+
+
+//##################################################################################################
+
+//
+// class CDelayMeterBinder  //
+//
+
+
+//
+// My constructor //
+//
+
+CDelayMeterBinder::CDelayMeterBinder():
+	CActive(CActive::EPriorityStandard),
+	iLowerControl(NULL),
+	iLowerDataSender(NULL),
+	iUpperControl(NULL),
+	iUpperDataReceiver(NULL)
+	{
+	}
+
+
+CDelayMeterBinder* CDelayMeterBinder::NewL()
+	{
+	CDelayMeterBinder* inst = new(ELeave) CDelayMeterBinder;
+	CleanupStack::PushL(inst);
+	inst->ConstructL();
+	CleanupStack::Pop(inst);
+	return inst;
+	}
+
+void CDelayMeterBinder::ConstructL()
+	{
+	CActiveScheduler::Add(this);
+
+	DelayMeter::DefinePubSubKeysL();
+
+	// watch for incoming commands
+	User::LeaveIfError(iProperty.Attach(TUid::Uid(KDelayMeterControlLevel), KCommandToDelayMeter));
+
+	iProperty.Subscribe(iStatus);
+	SetActive();
+	}
+
+/*virtual*/
+CDelayMeterBinder::~CDelayMeterBinder()
+	{
+	iSendRecorders.ResetAndDestroy();
+	iReceiveTimestampers.ResetAndDestroy();
+	DelayMeter::UndefinePubSubKeys();
+	}
+
+
+//
+// Methods from CActive (for pubsub control: //
+//
+
+/*virtual*/ void CDelayMeterBinder::DoCancel()
+	{
+	iProperty.Cancel();
+	}
+
+/*virtual*/ void CDelayMeterBinder::RunL()
+	{
+	// get command number from pub/sub key 0
+	TInt name=0;
+	iProperty.Get(name);
+
+	// get passed in buffer from pub/sub key KDataTransfer
+	HBufC8* buffer = HBufC8::New(RProperty::KMaxLargePropertySize);
+	User::LeaveIfNull(buffer);
+	CleanupStack::PushL(buffer);
+	TPtr8 ptr = buffer->Des();
+	RProperty::Get(TUid::Uid(KDelayMeterControlLevel), KDataTransfer, ptr);
+
+	// do the actual call
+	TInt ret = Control(KDelayMeterControlLevel,name,ptr);
+
+	// set the results buffer back to pub/sub key KDataTransfer
+	RProperty::Set(TUid::Uid(KDelayMeterControlLevel), KDataTransfer, ptr);
+	CleanupStack::PopAndDestroy(buffer);
+
+	// signal finished by writing return code to subkey KResponseFromDelayMeter. tear down the scheduler if we can't,
+	//   hopefully the deadlock will be noticed by the size of the explosion.
+	User::LeaveIfError(RProperty::Set(TUid::Uid(KDelayMeterControlLevel), KResponseFromDelayMeter, ret));
+
+	iProperty.Subscribe(iStatus);
+	SetActive();
+	}
+
+//
+// Methods from ESock::MLowerControl: //
+//
+
+TInt CDelayMeterBinder::GetName(TDes& aName)
+	{
+	TBuf16<10> tmp;
+	tmp.Copy(ProtocolName());
+	aName.Format(_L("delaymeter[%S][0x%08x]"), &tmp, this);
+
+	return KErrNone;
+	}
+
+TInt CDelayMeterBinder::BlockFlow(TBlockOption aOption)
+	{
+	if (iLowerControl==NULL)
+		{
+		return KErrNotReady;
+		}
+	return iLowerControl->BlockFlow(aOption) ;
+	}
+
+TInt CDelayMeterBinder::GetConfig(TBinderConfig& aConfig)
+	{
+	if (iLowerControl==NULL)
+		{
+		return KErrNotReady;
+		}
+	return iLowerControl->GetConfig(aConfig) ;
+	}
+
+
+TInt CDelayMeterBinder::Control(TUint aLevel, TUint aName, TDes8& aOption)
+	{
+	if (aLevel == KDelayMeterControlLevel)
+		{
+		if (aName <= KDelayMeterControl_NumberOfControlsPerInstance)
+			{
+			// prefs always passed in. on Start for initialisation,
+			//   on GetResults, for identification of which stamper/recorder to get results from
+			if (aOption.Length() < sizeof(TDelayMeterPrefs) )
+				{
+				return KErrCorrupt;
+				}
+			TUint8* ptr = const_cast<TUint8*>(aOption.Ptr());
+			TDelayMeterPrefs* prefs = reinterpret_cast<TDelayMeterPrefs*> (ptr);
+
+			TRAPD(result,ControlL(aName,aOption,*prefs));
+
+			return result;
+			}
+		else
+			{
+			// so it's for some instance below, so remove this "layer"...
+			aName -= KDelayMeterControl_NumberOfControlsPerInstance;
+			}
+		}
+
+	// Pass it on..
+	if (iLowerControl==NULL)
+		{
+		return KErrNotReady;
+		}
+	return iLowerControl->Control(aLevel,aName,aOption);
+	}
+
+
+void CDelayMeterBinder::ControlL(TUint aName, TDes8& aOption, TDelayMeterPrefs& prefs)
+	{
+	switch(aName)
+		{
+		case KDelayMeterControl_StartSendRecorder:
+			StartSendRecorderL(aOption,prefs);
+			break;
+
+		case KDelayMeterControl_GetSendRecorderResults:
+			GetSendRecorderResultsL(aOption,prefs);
+			break;
+
+		case KDelayMeterControl_StartReceiveTimestamper:
+			StartReceiveTimestamperL(aOption,prefs);
+			break;
+
+		case KDelayMeterControl_GetReceiveTimestamperResults:
+			GetReceiveTimestamperResultsL(aOption,prefs);
+			break;
+		}
+	}
+
+
+void CDelayMeterBinder::StartSendRecorderL(TDes8& aOption, TDelayMeterPrefs& prefs)
+	{
+	if (aOption.Length() != sizeof(TDelayMeterPrefs) )
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	if (FindSendRecorder(prefs.iProtocol, prefs.iDestinationPort))
+		{
+		User::Leave(KErrInUse);
+		}
+
+	CSendRecorder* newRecorder = new (ELeave) CSendRecorder;
+	CleanupStack::PushL(newRecorder);
+	newRecorder->SetupL(prefs);
+	iSendRecorders.AppendL(newRecorder);
+	CleanupStack::Pop(newRecorder);
+	}
+
+void CDelayMeterBinder::GetSendRecorderResultsL(TDes8& aOption, TDelayMeterPrefs& prefs)
+	{
+	CSendRecorder* recorder = FindSendRecorder(prefs.iProtocol,prefs.iDestinationPort, /*remove entry when found:*/ETrue);
+	if (recorder == NULL)
+		{
+		User::Leave(KErrNotReady);
+		}
+	CleanupStack::PushL(recorder); // I own this til its destruction
+
+	TInt nResults=0;
+	TDelaySampleSet* results=NULL;
+	recorder->GetResultsL(nResults,results);
+	TInt resultsLength=(nResults * sizeof(TDelaySampleSet));
+
+	if (aOption.Length() < resultsLength )
+		{
+		User::Leave(KErrOverflow);
+		}
+
+	TUint8* results_output = const_cast<TUint8*>(aOption.Ptr());
+	Mem::Copy(results_output,(TUint8*)(results),resultsLength);
+	aOption.SetLength(resultsLength);
+
+	CleanupStack::PopAndDestroy(recorder);
+	}
+
+void CDelayMeterBinder::StartReceiveTimestamperL(TDes8& aOption, TDelayMeterPrefs& prefs)
+	{
+	if (aOption.Length() != sizeof(TDelayMeterPrefs) )
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	if (FindReceiveTimestamper(prefs.iProtocol, prefs.iDestinationPort))
+		{
+		User::Leave(KErrInUse);
+		}
+
+	CReceiveTimestamper* newStamper = new (ELeave) CReceiveTimestamper;
+	CleanupStack::PushL(newStamper);
+	newStamper->SetupL(prefs);
+	iReceiveTimestampers.AppendL(newStamper);
+	CleanupStack::Pop(newStamper);
+	}
+
+void CDelayMeterBinder::GetReceiveTimestamperResultsL(TDes8& aOption, TDelayMeterPrefs& prefs)
+	{
+	CReceiveTimestamper* stamper = FindReceiveTimestamper(prefs.iProtocol,prefs.iDestinationPort, /*remove entry when found:*/ETrue);
+	if (stamper == NULL)
+		{
+		User::Leave(KErrNotReady);
+		}
+	CleanupStack::PushL(stamper); // I own this til its destruction
+
+	TInt nResults=0;
+	TDelaySampleSet* results=NULL;
+	stamper->GetResultsL(nResults,results);
+	TInt resultsLength=(nResults * sizeof(TDelaySampleSet));
+
+	if (aOption.Length() < resultsLength )
+		{
+		User::Leave(KErrOverflow);
+		}
+
+	TUint8* results_output = const_cast<TUint8*>(aOption.Ptr());
+	Mem::Copy(results_output,(TUint8*)(results),resultsLength);
+
+	CleanupStack::PopAndDestroy(stamper);
+	}
+
+//
+// Methods from ESock::MLowerDataSender: //
+//
+
+ESock::MLowerDataSender::TSendResult CDelayMeterBinder::Send(RMBufChain& aData)
+	{
+	if (iSendRecorders.Count())
+		{
+		RMBufChain payloadBufChain;
+		TInt protocol,port,statedLength;
+		if ( ExtractIPv4ProtocolAndPort(aData, /*returns*/payloadBufChain,protocol,port,statedLength))
+			{
+			// are we interested?
+			CSendRecorder* stamper = FindSendRecorder(protocol,port);
+			if (stamper)
+				{
+				if (payloadBufChain.Length() < statedLength)
+					{
+					// weird. we can't do anything with this.
+					ASSERT(1); // so we can set a breakpoint
+					NETPERF_TRACE_3(_L("CDelayMeterBinder::Send: stated size of packet (%d) doesn't match up with observed size (%d). Discarding packet.")
+							, statedLength, payloadBufChain.Length());
+					}
+				else
+					{
+					stamper->RecordDelay(payloadBufChain,statedLength);
+					}
+				}
+			}
+		}
+
+	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 CDelayMeterBinder::StartSending()
+	{
+	if (iUpperControl)
+		{
+		iUpperControl->StartSending();
+		}
+	else
+		{
+		ASSERT(1); // to allow setting a breakpoint
+		NETPERF_TRACE_1(_L("CDelayMeterBinder::StartSending: upper control not yet known!"));
+		}
+	}
+
+/*virtual*/
+void CDelayMeterBinder::Error(TInt anError)
+	{
+	if (iUpperControl)
+		{
+		iUpperControl->Error(anError);
+		}
+	else
+		{
+		ASSERT(1); // to set a breakpoint
+		NETPERF_TRACE_1(_L("CDelayMeterBinder::Error: upper control not yet known!"));
+		}
+	}
+
+
+//
+// Methods from ESock::MUpperDataReceiver: //
+//
+
+
+
+/*virtual*/
+void CDelayMeterBinder::Process(RMBufChain& aData)
+	{
+	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
+		NETPERF_TRACE_1(_L("CDelayMeterBinder::Process: incoming traffic discarded as upper data receiver not (or no longer) set"));
+		return;
+		}
+	if (iReceiveTimestampers.Count())
+		{
+		RMBufChain payloadBufChain;
+		TInt protocol,port,statedLength;
+		if ( ExtractIPv4ProtocolAndPort(aData, /*returns*/payloadBufChain,protocol,port,statedLength))
+			{
+			// are we interested?
+			CReceiveTimestamper* stamper = FindReceiveTimestamper(protocol,port);
+			if (stamper)
+				{
+				//	TInt statedLength = udpStatedLength + 20 /*ip header*/ ;
+				if (payloadBufChain.Length() < statedLength)
+					{
+					// weird. we can't do anything with this.
+					ASSERT(1); // so we can set a breakpoint
+					NETPERF_TRACE_3(_L("CDelayMeterBinder::Process: stated size of packet (%d) doesn't match up with observed size (%d). Discarding packet.")
+							, statedLength, payloadBufChain.Length());
+					}
+				else
+					{
+					stamper->Timestamp(payloadBufChain,statedLength);
+					}
+				}
+			else
+				{
+				NETPERF_TRACE_1(_L("CDelayMeterBinder::Process: incoming traffic not stamped as no matching stamper found"));
+				}
+			}
+		}
+	else
+		{
+		NETPERF_TRACE_1(_L("CDelayMeterBinder::Process: incoming traffic not stamped as no stampers are configured"));
+		}
+
+
+	iUpperDataReceiver->Process(aData);
+	}
+
+
+//
+// and my own methods.. //
+//
+
+// called by layer above calling my flow's BindL
+void CDelayMeterBinder::BindToUpperL(MUpperDataReceiver& aUpperDataReceiver, MUpperControl& aUpperControl)
+	{
+	if (iUpperDataReceiver || iUpperControl) {User::Leave(KErrInUse);}
+	iUpperDataReceiver=&aUpperDataReceiver;
+	iUpperControl=&aUpperControl;
+	}
+
+// called by layer above calling my flow's Unbind. Returns ETrue if unbind happened here, EFalse otherwise
+TBool CDelayMeterBinder::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 CDelayMeterBinder::BindToLowerFlowL(ESock::MFlowBinderControl& aLowerBinderControl)
+	{
+	if (iLowerControl || iLowerDataSender)
+		{
+		User::Leave(KErrInUse);
+		}
+	iLowerControl = aLowerBinderControl.GetControlL(ProtocolName());
+	iLowerDataSender = aLowerBinderControl.BindL(ProtocolName(), this, this);
+	}
+
+const TDesC8& CDelayMeterBinder::ProtocolName() const
+	{
+	return KIp4ProtocolName;
+	}
+
+
+CSendRecorder* CDelayMeterBinder::FindSendRecorder(TInt aProtocol, TInt aPortNumber, TBool aRemoveFoundEntry)
+	{
+	for (TInt i=0;i<iSendRecorders.Count();++i)
+		{
+		CSendRecorder* recorder = iSendRecorders[i];
+		if (recorder->iPrefs.iDestinationPort == aPortNumber &&
+		   recorder->iPrefs.iProtocol == aProtocol )
+			{
+			if (aRemoveFoundEntry)
+				{
+				iSendRecorders.Remove(i);
+				}
+			return recorder;
+			}
+		}
+	return NULL;
+	}
+
+CReceiveTimestamper* CDelayMeterBinder::FindReceiveTimestamper(TInt aProtocol, TInt aPortNumber, TBool aRemoveFoundEntry)
+	{
+	for (TInt i=0;i<iReceiveTimestampers.Count();++i)
+		{
+		CReceiveTimestamper* sender = iReceiveTimestampers[i];
+		if (sender->iPrefs.iDestinationPort == aPortNumber &&
+		   sender->iPrefs.iProtocol == aProtocol )
+			{
+			if (aRemoveFoundEntry)
+				{
+				iReceiveTimestampers.Remove(i);
+				}
+			return sender;
+			}
+		}
+	return NULL;
+	}
+
+TBool CDelayMeterBinder::ExtractIPv4ProtocolAndPort(RMBufChain& aData,
+											/*returns: */ RMBufChain& aPayload, TInt& aProtocol, TInt& aPort, TInt& aLength)
+	{
+	RMBuf* mbuf = aData.First();
+	ASSERT(mbuf);
+	ASSERT(mbuf->Type()==EMBufHeader);
+	mbuf=mbuf->Next();
+	ASSERT(mbuf);
+	ASSERT(mbuf->Type()==EMBufData);  // this should be smart enough..
+	aPayload = mbuf;
+
+	if (aPayload.Align(38) != 38) return EFalse; // cover whole IP+(UDP/TCP ports) header, and
+							// TCP header up to checksum (which covers UDP checksum too)
+
+	TUint8* payload = mbuf->Ptr();
+
+	//check IP version (4) and IP header length(5*4))
+	if (payload[0] != (TInt8)0x45) return EFalse;
+	//check that there is no IP fragmentation
+	if ((payload[6] & (~0x40)) != (TInt8)0  || payload[7] != (TInt8)0) return EFalse;
+
+	//extract protocol, port, length..
+	aProtocol = payload[9];
+	aPort = (payload[22]<<8) + payload[23];
+	aLength = (payload[2]<<8) + payload[3];
+	return ETrue;
+	}
+
+
+