--- /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;
+ }
+
+
+