--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networkingtestandutils/exampleinternetutilities/TRENG/TRENG.CPP Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,882 @@
+// Copyright (c) 1998-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:
+//
+
+#include <treng.h>
+#include <e32hal.h>
+#include <icmp6_hdr.h>
+#include <in_chk.h>
+#include <commdbconnpref.h>
+
+const TUint KDefaultMaxTtl = 30;
+const TInt KDefaultWait = 5000000;
+const TInt KDefaultNrProbes = 3;
+
+const TInt KMinIpHeaderSize = 20;
+const TInt KMaxSendTime=60000000;
+const TInt KRecvDataSize=512;
+const TInt KResolvTime=10000000;
+
+const TInt KIcmpHeaderSize = 8;
+
+class CTraceRtTimer : public CTimer
+ {
+friend class CTraceRtEng;
+protected:
+ CTraceRtTimer(CTraceRtEng& aParent);
+ void RunL();
+private:
+ CTraceRtEng* iParent;
+ };
+
+class CTraceRtSender : public CActive
+ {
+friend class CTraceRtEng;
+protected:
+ CTraceRtSender(CTraceRtEng& aParent);
+ ~CTraceRtSender();
+ void RunL();
+ void DoCancel();
+private:
+ CTraceRtEng* iParent;
+ };
+
+class CTraceRtReceiver : public CActive
+ {
+friend class CTraceRtEng;
+protected:
+ CTraceRtReceiver(CTraceRtEng& aParent);
+ ~CTraceRtReceiver();
+ void RunL();
+ void DoCancel();
+private:
+ CTraceRtEng* iParent;
+ };
+
+
+// Class to manage ICMP headers information
+class HTraceRtHeader : public TInet6HeaderICMP_Echo
+ {
+public:
+ static HTraceRtHeader* NewL(TInt aSize = KIcmpHeaderSize);
+ ~HTraceRtHeader();
+
+ TBool VerifyRecv(TInt aIdent, TInt aSeq);
+ void FormatSend(TUint aId, TUint aSeq);
+ TInt MaxLength();
+ TInt DataLength();
+ TPtr8* Grab();
+
+private:
+ void ConstructL(TInt aSize);
+ TBool SetHeader(TUint aOffset = 0);
+
+ HBufC8* iData;
+ TPtr8* iDataPtr; // Packet data
+ };
+
+enum TTraceRtEngPanic
+ {
+
+ ETimerPriorityGreaterThanSender, // 0
+ ESenderPrirityGreaterThanReceiver // 1
+ };
+
+LOCAL_C void Panic(TTraceRtEngPanic aPanic)
+//
+// Panic the user
+//
+ {
+
+ User::Panic(_L("TraceRtEng"), aPanic);
+ }
+
+EXPORT_C TTraceRtOptions::TTraceRtOptions()
+//
+// Default TraceRt options
+//
+ {
+
+ iMaxTtl=KDefaultMaxTtl;
+ iResolveAddress=ETrue;
+ iWait=KDefaultWait;
+ iTos=0;
+ iDestname.SetLength(0);
+ iNrProbes=KDefaultNrProbes;
+ iPrompt = EFalse;
+ }
+
+EXPORT_C CTraceRtEng* CTraceRtEng::NewL(MTraceRtNotificationHandler& aUi)
+//
+// Create a new TraceRt engine
+//
+ {
+
+ CTraceRtEng* p= new(ELeave) CTraceRtEng;
+ CleanupStack::PushL(p);
+ p->ConstructL(aUi);
+ CleanupStack::Pop();
+ return p;
+ }
+
+EXPORT_C CTraceRtEng::CTraceRtEng()
+//
+// Declare a name
+//
+ {
+
+ __DECLARE_NAME(_S("CTraceRtEng"));
+ }
+
+EXPORT_C CTraceRtEng::~CTraceRtEng()
+//
+// Destroy wot TraceRt created
+ {
+
+ iIcmpSocket.Close();
+ iResolver.Close();
+ iConnect.Close();
+ iSocketServ.Close();
+ delete iReceiver;
+ delete iSender;
+ delete iTimer;
+ delete iRecvData;
+ delete iSendData;
+ }
+
+EXPORT_C void CTraceRtEng::ConstructL(MTraceRtNotificationHandler& aUi)
+//
+// Construct and heap objects
+//
+ {
+
+ iUi = &aUi;
+ iTimer = new (ELeave) CTraceRtTimer(*this);
+ iTimer->ConstructL();
+ iSender = new (ELeave) CTraceRtSender(*this);
+ iReceiver = new (ELeave) CTraceRtReceiver(*this);
+ User::LeaveIfError(iSocketServ.Connect());
+ iSendData = NULL;
+ iRecvData = NULL;
+ iResolv = EFalse;
+ }
+
+EXPORT_C void CTraceRtEng::SetPriorities(TInt aTimerPriority, TInt aSenderPriority, TInt aReceiverPriority)
+//
+// Set various active object priorities
+//
+ {
+
+ __ASSERT_ALWAYS(aTimerPriority < aSenderPriority, Panic(ETimerPriorityGreaterThanSender));
+ __ASSERT_ALWAYS(aSenderPriority < aReceiverPriority, Panic(ESenderPrirityGreaterThanReceiver));
+
+ iTimer->SetPriority(aTimerPriority);
+ iSender->SetPriority(aSenderPriority);
+ iReceiver->SetPriority(aReceiverPriority);
+ }
+
+EXPORT_C void CTraceRtEng::Start(const TTraceRtOptions& aOptions)
+//
+// Start a TraceRt
+//
+ {
+
+ // Reset All Variables
+ iProbeNr=0;
+ iTtl=1;
+ iSeq=0;
+ iNameEntry().iName.SetLength(0);
+ iNameEntry().iFlags=0;
+ TInetAddr::Cast(iNameEntry().iAddr).SetAddress(0);
+ iGotThere=EFalse;
+ iUnreachCount=0;
+ iIdent=User::TickCount()&KMaxTUint16;
+ iLastCode=KTraceRtCodeTimeout;
+
+ iOptions=aOptions;
+
+
+ if(iOptions.iMaxTtl>255 || iOptions.iTos>255
+ || iOptions.iNrProbes>100 || iOptions.iNrProbes<1)
+ {
+ DoError(KErrNotSupported);
+ return;
+ }
+
+ if(iSendData)
+ {
+ delete iSendData;
+ }
+ iSendData = HTraceRtHeader::NewL(KIcmpHeaderSize);
+
+ if(iRecvData)
+ {
+ delete iRecvData;
+ }
+ iRecvData = HTraceRtHeader::NewL(KRecvDataSize);
+
+ if(!iRecvData || !iSendData)
+ {
+ DoError(KErrNoMemory);
+ }
+ else if(iOptions.iDestname.Length()>0)
+ {
+ iConnect.Close();
+ User::LeaveIfError(iConnect.Open(iSocketServ, KConnectionTypeDefault));
+
+ TCommDbConnPref commDbPref;
+ if(!iOptions.iPrompt)
+ {
+ commDbPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
+ }
+ else
+ {
+ commDbPref.SetDialogPreference(ECommDbDialogPrefPrompt);
+ }
+ User::LeaveIfError(iConnect.Start(commDbPref));
+
+ TInt err=iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp, iConnect);
+ if(err==KErrNone)
+ {
+
+ TInetAddr& addr = (TInetAddr&)iNameEntry().iAddr;
+ if ((err=addr.Input(iOptions.iDestname))==KErrNone)
+ {
+
+ if(iOptions.iResolveAddress)
+ {
+ iState=ELookingUpHost;
+ iResolver.GetByAddress(addr, iNameEntry, iSender->iStatus);
+ iSender->SetActive();
+ iTimer->After(KResolvTime);
+ }
+ else
+ {
+ iSender->iStatus=KErrNone;
+ iState=ELookingUpHost;
+ SendComplete();
+ }
+ }
+ else
+ {
+ iState=ELookingUpHost;
+ iResolver.GetByName(iOptions.iDestname, iNameEntry, iSender->iStatus);
+
+ iSender->SetActive();
+ iTimer->After(KResolvTime);
+ }
+ }
+ else
+ {
+ DoError(err);
+ }
+ }
+ else
+ {
+ DoError(KErrBadName);
+ }
+ }
+
+EXPORT_C void CTraceRtEng::CancelAndFinished()
+//
+// Cancel from the UI
+//
+ {
+
+ if(iState!=EStopped || iTimer->IsActive())
+ {
+ Cancel();
+ iUi->Finished(KErrCancel);
+ }
+ }
+
+EXPORT_C void CTraceRtEng::Cancel()
+//
+// Cancel a TraceRt in progress
+//
+ {
+
+ iSender->Cancel();
+ iReceiver->Cancel();
+ iTimer->Cancel();
+
+ iIcmpSocket.Close();
+ iResolver.Close();
+
+ iState=EStopped;
+ }
+
+void CTraceRtEng::DoError(TInt aError)
+//
+// Generate an error from somewhere
+//
+ {
+
+ Cancel();
+ iTimer->SetActive();
+ TRequestStatus* p = &iTimer->iStatus;
+ User::RequestComplete(p, aError);
+ }
+
+void CTraceRtEng::TimerComplete()
+//
+// Timer event completed
+//
+ {
+
+ if(iTimer->iStatus==KErrNone)
+ {
+
+ if(iSender->IsActive())
+ {
+ if(iResolv)
+ {
+ // We didn't manage to get the name
+ // from the address, so we pass on
+ iResolv = EFalse;
+ // Reset sender
+ iSender->Cancel();
+ // Clear previous name
+ iNameEntry().iName.SetLength(0);
+ // Continue
+ NextSend();
+ }
+ else
+ {
+ Cancel();
+ iUi->Finished(KErrTimedOut);
+ }
+ }
+ else
+ {
+ iUi->Reply(iProbeNr, 0, KTraceRtCodeTimeout);
+ switch(iLastCode)
+ {
+ case KTraceRtCodeUnreachNet:
+ case KTraceRtCodeUnreachHost:
+ ++iUnreachCount;
+ break;
+ default:
+ break;
+ }
+ NextSend();
+ }
+ }
+ else
+ {
+ Cancel();
+ iUi->Finished(iTimer->iStatus.Int());
+ }
+ }
+
+void CTraceRtEng::SendComplete()
+//
+// A send operation has completed
+//
+ {
+
+ TInt err=iSender->iStatus.Int();
+ iTimer->Cancel();
+ iResolv = EFalse;
+
+ switch(iState)
+ {
+
+ case ELookingUpHost:
+ iDstAddr = iNameEntry().iAddr;
+ if(iDstAddr.Address()!=0)
+ {
+ TInt res=iIcmpSocket.Open(iSocketServ, KAfInet, KSockDatagram, KProtocolInetIcmp, iConnect);
+
+ if(res==KErrNone)
+ {
+ res=iIcmpSocket.SetOpt(KSORecvBuf, KSOLSocket, iRecvData->MaxLength());
+ }
+ if(res==KErrNone)
+ {
+ res=iIcmpSocket.SetOpt(KSOSendBuf, KSOLSocket, iSendData->MaxLength());
+ }
+ if(res==KErrNone)
+ {
+ res=iIcmpSocket.SetOpt(KSoIpTOS, KSolInetIp, (TInt)iOptions.iTos);
+ }
+
+ if(res!=KErrNone)
+ {
+ DoError(res);
+ return;
+ }
+
+ // Tell the UI
+ iUi->Starting(iNameEntry(), iOptions.iMaxTtl, iSendData->MaxLength());
+ iState=ESending;
+ NextSend();
+ }
+ else
+ {
+ DoError(err!=KErrNone ? err : KErrNotFound);
+ }
+ break;
+
+ case ELookingUpReply:
+ if(err!=KErrNone)
+ {
+ iNameEntry().iName.SetLength(0);
+ }
+ NextSend();
+ break;
+
+ default:
+ if(err==KErrNone)
+ {
+ iTimer->After(iOptions.iWait);
+ iIcmpSocket.RecvFrom(*(iRecvData->Grab()), iSrcAddr, 0, iReceiver->iStatus);
+ iReceiver->SetActive();
+ }
+ else
+ {
+ DoError(err);
+ }
+ }
+ }
+
+void CTraceRtEng::NextSend()
+//
+// Initiate the next send
+//
+ {
+
+ iReceiver->Cancel();
+
+ if(iProbeNr>=iOptions.iNrProbes)
+ {
+
+ if(iState==ELookingUpReply || !iOptions.iResolveAddress || TInetAddr::Cast(iNameEntry().iAddr).Address()==0)
+ {
+
+ if(!iOptions.iResolveAddress)
+ {
+ iNameEntry().iName.SetLength(0);
+ }
+
+ iUi->FromHost(iNameEntry());
+ if(iGotThere || iUnreachCount>=iOptions.iNrProbes )
+ {
+ Cancel();
+ iUi->Finished(KErrNone);
+ return;
+ }
+
+ TInetAddr::Cast(iNameEntry().iAddr).SetAddress(0);
+ ++iTtl;
+ iProbeNr=0;
+ iLastCode=KTraceRtCodeTimeout;
+ iUnreachCount=0;
+ iState=ESending;
+ }
+ else
+ {
+ iState=ELookingUpReply;
+
+ // Work around for bug in pre-61 versions of TCPIP
+ TProtocolDesc info;
+ if(iIcmpSocket.Info(info)==KErrNone)
+ {
+ TVersion &v=info.iVersion;
+ if(v.iMajor==1 && v.iMinor==0 && v.iBuild<61)
+ {
+ iResolver.Close();
+ TInt res=iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp, iConnect);
+ if(res!=KErrNone)
+ {
+ DoError(res);
+ return;
+ }
+ }
+ }
+ // Work around ends
+
+ iResolver.GetByAddress(iNameEntry().iAddr, iNameEntry, iSender->iStatus);
+ iSender->SetActive();
+ iResolv = ETrue;
+ iTimer->After(KResolvTime);
+ return;
+ }
+ }
+
+ if(iTtl>iOptions.iMaxTtl)
+ {
+ Cancel();
+ iUi->Finished(KErrNone);
+ return;
+ }
+
+ if(iProbeNr==0)
+ {
+ iUi->Probe(iTtl);
+ }
+
+ iSendData->FormatSend(++iSeq, iIdent);
+ TInt res=iIcmpSocket.SetOpt(KSoIpTTL, KSolInetIp, (TInt)iTtl);
+ if(res!=KErrNone)
+ {
+ DoError(res);
+ return;
+ }
+ iIcmpSocket.SendTo(*(iSendData->Grab()), iDstAddr, 0, iSender->iStatus);
+ iSendTime.UniversalTime();
+ iSender->SetActive();
+ iTimer->After(KMaxSendTime);
+// pg 13/03/2000 - Base removing this api
+// UserHal::ResetAutoSwitchOffTimer();
+
+ ++iProbeNr;
+ return;
+ }
+
+void CTraceRtEng::SendDoCancel()
+//
+// A send operation requires cancelling
+//
+ {
+
+ if(iState==ELookingUpHost || iState==ELookingUpReply)
+ {
+ iResolver.Cancel();
+ }
+ else if(iState==ESending)
+ {
+ iIcmpSocket.CancelSend();
+ }
+ }
+
+void CTraceRtEng::RecvComplete()
+//
+// A recv operation has completed
+//
+ {
+
+ if(iReceiver->iStatus==KErrNone)
+ {
+
+ if(iState!=ESending)
+ {
+ return;
+ }
+
+ if(iRecvData->VerifyRecv(iSeq, iIdent))
+ {
+
+ iNameEntry().iAddr = iSrcAddr;
+ TTime now;
+ now.UniversalTime();
+ TTimeIntervalMicroSeconds delta = now.MicroSecondsFrom(iSendTime);
+ TUint code;
+
+ switch(iRecvData->Type())
+ {
+ case KTraceRtTypeTimeExceeded:
+ code = KTraceRtCodeTimedOutInTransit;
+ break;
+ case KTraceRtTypeEchoReply:
+ code = KTraceRtCodeEchoReply;
+ iGotThere=ETrue;
+ break;
+ default:
+ code=iRecvData->Code();
+ ++iUnreachCount;
+ }
+
+ iLastCode=code;
+
+ delta = delta.Int64()/TInt64(1000);
+ iUi->Reply(iProbeNr, I64LOW(delta.Int64()), code);
+
+ iTimer->Cancel();
+ NextSend();
+ return;
+ }
+ if(!iSender->IsActive())
+ {
+ iLastCode = iRecvData->Code();
+ iIcmpSocket.RecvFrom(*(iRecvData->Grab()), iSrcAddr, 0, iReceiver->iStatus);
+ iReceiver->SetActive();
+ }
+ }
+ else
+ {
+ DoError(iReceiver->iStatus.Int());
+ }
+ }
+
+void CTraceRtEng::RecvDoCancel()
+//
+// A send operation requires cancelling
+//
+ {
+
+ iIcmpSocket.CancelRecv();
+ }
+
+CTraceRtTimer::CTraceRtTimer(CTraceRtEng& aParent)
+//
+// To time events
+//
+ : CTimer(ETraceRtTimerPriority)
+ {
+
+ iParent = &aParent;
+ CActiveScheduler::Add(this);
+ __DECLARE_NAME(_S("CTraceRtTimer"));
+ }
+
+void CTraceRtTimer::RunL()
+//
+// Timer is complete
+//
+ {
+
+ iParent->TimerComplete();
+ }
+
+CTraceRtSender::CTraceRtSender(CTraceRtEng& aParent)
+//
+// C'tor
+//
+ : CActive(ETraceRtSenderPriority)
+ {
+
+ iParent = &aParent;
+ CActiveScheduler::Add(this);
+ __DECLARE_NAME(_S("CTraceRtSender"));
+ }
+
+CTraceRtSender::~CTraceRtSender()
+//
+// D'tor cancels
+//
+ {
+
+ Cancel();
+ }
+
+void CTraceRtSender::RunL()
+//
+// Upcall to parent
+//
+ {
+
+ iParent->SendComplete();
+ }
+
+void CTraceRtSender::DoCancel()
+//
+// Get parent to cancel send
+//
+ {
+
+ iParent->SendDoCancel();
+ }
+
+CTraceRtReceiver::CTraceRtReceiver(CTraceRtEng& aParent)
+//
+// C'tor
+//
+ : CActive(ETraceRtReceiverPriority)
+ {
+
+ iParent = &aParent;
+ CActiveScheduler::Add(this);
+ __DECLARE_NAME(_S("CTraceRtReceiver"));
+ }
+
+CTraceRtReceiver::~CTraceRtReceiver()
+//
+// D'tor cancels
+//
+ {
+
+ Cancel();
+ }
+
+void CTraceRtReceiver::RunL()
+//
+// Upcall to parent
+//
+ {
+
+ iParent->RecvComplete();
+ }
+
+void CTraceRtReceiver::DoCancel()
+//
+// Get parent to cancel send
+//
+ {
+
+ iParent->RecvDoCancel();
+ }
+
+
+HTraceRtHeader::~HTraceRtHeader()
+//
+// D'tor deletes
+//
+ {
+
+ delete iData;
+ delete iDataPtr;
+ }
+
+HTraceRtHeader* HTraceRtHeader::NewL(TInt aSize)
+//
+// Create a new trace route header
+//
+ {
+
+ HTraceRtHeader* h = new(ELeave) HTraceRtHeader();
+
+ CleanupStack::PushL(h);
+ h->ConstructL(aSize);
+ CleanupStack::Pop(h);
+
+ return h;
+ }
+
+void HTraceRtHeader::ConstructL(TInt aSize)
+ {
+
+ iData = HBufC8::NewL(aSize);
+ iDataPtr = new(ELeave) TPtr8(iData->Des());
+
+ iData->Des().FillZ();
+ }
+
+TInt HTraceRtHeader::MaxLength()
+ {
+
+ return iData->Des().MaxLength();
+ }
+
+TInt HTraceRtHeader::DataLength()
+ {
+
+ return iData->Des().Length();
+ }
+
+TPtr8* HTraceRtHeader::Grab()
+ {
+
+ iDataPtr->Copy(iData->Des());
+ return iDataPtr;
+ }
+
+TBool HTraceRtHeader::SetHeader(TUint aOffset)
+//
+// Set the header from an Icmp reply
+//
+ {
+
+ const TUint8* buffData;
+
+ // Check size
+ if(DataLength() < KIcmpHeaderSize)
+ {
+ return EFalse;
+ }
+
+ buffData = iData->Des().Ptr();
+
+ if(!buffData)
+ {
+ return EFalse;
+ }
+
+ // Fill TInet6HeaderICMP_Echo from the buffer
+ for(int k=0;k<KIcmpHeaderSize;k++)
+ {
+ i[k] = *(buffData + k + aOffset);
+ }
+
+ return ETrue;
+ }
+
+TBool HTraceRtHeader::VerifyRecv(TInt aSeq, TInt aIdent)
+//
+// Verify header is valid
+//
+ {
+
+ TBool ret = SetHeader();
+
+ if(ret)
+ {
+ ret = EFalse;
+
+ if(Type() == KTraceRtTypeEchoReply && Identifier() == aIdent && Sequence() == aSeq)
+ {
+ ret = ETrue;
+ }
+
+ if(!ret && ((Type() == KTraceRtTypeTimeExceeded && Code() == KTraceRtCodeExceedInTransit) || Type() == KTraceRtTypeUnreachable))
+ {
+ TUint code = Code();
+ TUint type = Type();
+ ret = SetHeader(KMinIpHeaderSize + KIcmpHeaderSize);
+
+ if(ret)
+ {
+ ret = EFalse;
+
+ if(Type() != KTraceRtTypeEchoRequest || Identifier() != aIdent || Sequence() != aSeq)
+ {
+ ret = EFalse;
+ }
+ else
+ {
+ ret = ETrue;
+ }
+ }
+ SetCode(static_cast<TUint8>(code));
+ SetType(static_cast<TUint8>(type));
+ }
+ }
+
+ return ret;
+ }
+
+
+void HTraceRtHeader::FormatSend(TUint aSeq, TUint aIdent)
+//
+// Format an ICMP Header
+//
+ {
+
+ TChecksum sum;
+
+ // Fill header
+ SetType(KTraceRtTypeEchoRequest);
+ SetCode(KTraceRtCodeEcho);
+ SetIdentifier(static_cast<TUint16>(aIdent));
+ SetSequence(static_cast<TUint16>(aSeq));
+
+ // Compute cheksum
+ SetChecksum(0);
+ sum.Add(reinterpret_cast<TUint16*>(this), HeaderLength());
+ SetChecksum(sum.Sum());
+
+ // Copy the ICMP Header in the buffer
+ iData->Des().Copy((TUint8*)this, HeaderLength());
+ }
+