networkingtestandutils/ipprobe/src/prt.cpp
changeset 25 d15a50675083
parent 0 af10295192d8
child 58 8d540f55e491
--- a/networkingtestandutils/ipprobe/src/prt.cpp	Fri May 14 17:24:38 2010 +0300
+++ b/networkingtestandutils/ipprobe/src/prt.cpp	Thu May 27 14:26:17 2010 +0300
@@ -1,34 +1,50 @@
-// Copyright (c) 2004-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:
-// prt.cpp - Packet Probe Hook
-//
+/*
+* Copyright (c) 2009-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: Packet probe hook
+*
+*/
 
 #include <e32std.h>
 #include <e32base.h>
+#include <f32file.h>
+#include <e32svr.h>
 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
 #include <es_prot_internal.h>
 #endif
 
+
 #include "family.h"
 #include "prt.h"
 #include "sap.h"
 #include "inet6log.h"
+_LIT(KTcpDumpFolder, "tcpdump\\");
+_LIT(KProbeDumpFile, "probe.cap");
+_LIT(KLogFolder,     "c:\\logs\\");
 
 
-CProtocolProbe::CProtocolProbe(TUint aId) : iId(aId)
+CProtocolProbe::CProtocolProbe(TUint aId) : 
+iId(aId), 
+iDumpCb(CActive::EPriorityStandard),
+iFileServerOpen(EFalse),
+iFileOpen(EFalse),
+iBufCreated(EFalse)
 	{
 	LOG(Log::Printf(_L("Probe::CProtocolProbe()\r\n"));)
+	iTimeOrigin.UniversalTime();
+
+	TCallBack cbFunc(DumpCb, this);
+	iDumpCb.Set(cbFunc);
 	}
 
 void CProtocolProbe::InitL(TDesC& aTag)
@@ -37,7 +53,6 @@
 	CProtocolBase::InitL(aTag);
 	}
 
-
 void CProtocolProbe::StartL()
 	{
 	//	__ASSERT_DEBUG(iProtocol != NULL, User::Leave(KErrGeneral));
@@ -45,20 +60,39 @@
 
 CProtocolProbe::~CProtocolProbe()
 	{
-	LOG(Log::Printf(_L("Probe::~CProtocolProbe()\r\n"));)
+	LOG(Log::Printf(_L("Probe::~CProtocolProbe()\r\n"));)	
+	if(iFileOpen)
+	    {
+		iFile.Close();
+		iFileOpen = EFalse;
+	    }
+	if(iFileServerOpen)
+		{
+		iFs.Close();
+		iFileServerOpen = EFalse;
+		}	
+    if(iBufCreated)
+        {
+        iBuf.Close();
+        iBufCreated = EFalse;
+        }
 	}
 
-
 CProtocolProbe *CProtocolProbe::NewL(TUint aId)
 	{
+
 	return new (ELeave) CProtocolProbe(aId);
 	}
 
 void CProtocolProbe::FillIdentification(TServerProtocolDesc& anEntry, TUint aId)
 	{
+
 	anEntry.iName=_S("probe");
 	if (aId > 1)
+		{
 		anEntry.iName.AppendNum(aId-1);
+		}
+
 	anEntry.iAddrFamily = KAfProbe;
 	anEntry.iSockType = KSockDatagram;
 	anEntry.iProtocol = aId;
@@ -83,7 +117,10 @@
 	LOG(Log::Printf(_L("Probe::NewSAPL(%d)\r\n"), aProtocol);)
 
 	if (aProtocol != KSockDatagram)
+		{
 		User::Leave(KErrNotSupported);
+		}
+
 	CProviderProbe* sap = new (ELeave) CProviderProbe(this);
 	sap->iNext = iList;
 	iList = sap;
@@ -97,6 +134,7 @@
 //
 void CProtocolProbe::CancelSAP(const CServProviderBase* aSAP)
 	{
+	
 	CProviderProbe **h, *sap;
 	for (h = &iList; (sap = *h) != NULL; h = &sap->iNext)
 		if (sap == aSAP)
@@ -106,49 +144,218 @@
 			}
 	}
 
-
 // CProtocolProbe::NetworkAttachedL
 // ********************************
 // When network becomes available, do the hooking!
 //
 void CProtocolProbe::NetworkAttachedL()
 	{
+
 	NetworkService()->BindL(this, MIp6Hook::BindPostHook());
 	NetworkService()->BindL(this, MIp6Hook::BindPostHook()+1);
+
+	// initialise dump file
+	if(iFileOpen)
+		{
+		iFile.Close();
+		iFileOpen = EFalse;
+		}
+	if(iFileServerOpen)
+		{
+		iFs.Close();
+		iFileServerOpen = EFalse;
+		}
+
+	User::LeaveIfError(iFs.Connect());
+    iFileServerOpen = ETrue;
+    TBuf<50> filename;
+    filename.Append(KLogFolder);
+    filename.Append(KTcpDumpFolder);
+    filename.Append(KProbeDumpFile);
+	User::LeaveIfError(iFile.Replace(iFs, filename, EFileWrite));
+    iFileOpen = ETrue;
+
+    // allocate buffer
+    if(!iBufCreated)
+        {
+		const TInt KMaxBufferSize = 65535;
+        iBuf.CreateL(KMaxBufferSize);
+        iBufCreated = ETrue;
+        }
+    
+	LibcapDumpFileHeader();
 	}
 
+void CProtocolProbe::Queue(RMBufChain &aPacket)
 //
-//	CProtocolProbe::Deliver
-//	***********************
-//	Generate a copy of the packet to every bound provider
+//  Takes a copy of aPacket, adds it to the queue and triggers the callback
 //
-void CProtocolProbe::Deliver(RMBufChain &aPacket)
 	{
-	const RMBufPktInfo *const info = RMBufPacketBase::PeekInfoInChain(aPacket);
+
+	RMBufPacketBase copy;
+	TRAPD(err, copy.CopyPackedL(aPacket));
+	if (err == KErrNone)
+		{
+
+		//
+		// Calculate packet time-stamp
+		//
+		TTime newTime;
+		newTime.UniversalTime();
+		TTimeIntervalMicroSeconds interval = newTime.MicroSecondsFrom(iTimeOrigin);
+
+		const TInt KMicrosInASecond = 1000000;
 
-	for (CProviderProbe* sap = iList; sap != NULL; sap = sap->iNext)
+		//TUint32 micros = interval.Int64().Low();
+		TUint32 micros = I64LOW(interval.Int64());//.Low();  x.Low() -> I64LOW(x)
+		TUint32 secs = micros / KMicrosInASecond;
+		micros -= (secs * KMicrosInASecond);
+
+		//
+		// Reuse the protocol and flags fields of
+		// RMBufPktInfo to store the time-stamp
+		//
+		RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(copy);
+		info->iProtocol = static_cast<TInt>(secs);
+		info->iFlags = static_cast<TUint>(micros);
+
+		iQueue.Append(copy);
+		iDumpCb.CallBack();
+		}
+	else
 		{
-		if (sap->IsReceiving(*info))
-			{
-			RMBufPacketBase copy;
-			TRAPD(err, copy.CopyPackedL(aPacket));
-			if (err == KErrNone)
-				sap->Process(copy, this);
-			else
-				copy.Free();
-			}
+		copy.Free();
 		}
 	}
 
 
+//
+//	CProtocolProbe::Dump
+//	***********************
+//	Log the packet to file
+//
+void CProtocolProbe::Dump(RMBufChain &aPacket)
+	{
+
+	RMBufPacket packet;
+	packet.Assign(aPacket);
+	RMBufPktInfo* info = packet.Unpack();
+
+	TUint32 secs = static_cast<TUint32>(info->iProtocol);
+	TUint32 micros = static_cast<TUint32>(info->iFlags);
+
+    iBuf.SetMax();
+    packet.CopyOut(iBuf, 0);
+    if(iBuf.Length() != info->iLength)
+        {
+        iBuf.SetLength(info->iLength);
+        }
+	LibcapDump(iBuf, secs, micros);
+	packet.Free();
+	}
+
 TInt CProtocolProbe::Send(RMBufChain &aPacket, CProtocolBase* aSrc)
 	{
-	Deliver(aPacket);
+
+	Queue(aPacket);
 	return CProtocolPosthook::Send(aPacket, aSrc);
 	}
 
 void CProtocolProbe::Process(RMBufChain &aPacket, CProtocolBase* aSrc)
 	{
-	Deliver(aPacket);
+
+	Queue(aPacket);
 	CProtocolPosthook::Process(aPacket, aSrc);
 	}
+
+void CProtocolProbe::LibcapDumpFileHeader()
+//
+//  Dump file header in a format compatible with Libcap
+//
+//  Format is:
+//  
+//  struct FileHeader
+//      {
+//	    TUint32 magic; 
+//	    TUint16 version_major;
+//	    TUint16 version_minor;
+//	    TUint32 thiszone;	/* gmt to local correction */
+//	    TUint32 sigfigs;	/* accuracy of timestamps */
+//	    TUint32 snaplen;	/* max length saved portion of each pkt */
+//	    TUint32 linktype;	/* data link type (LINKTYPE_*) */
+//      };
+//
+//  Note LINKTYPE specified in libpcap/bpf/net/bpf.h (see www.tcpdump.org)
+//
+	{
+
+	TBuf8<sizeof(TUint32)*5+sizeof(TUint16)*2> fileHeader;
+	*((TUint32*) &(fileHeader.Ptr()[0])) = 0xa1b2c3d4;
+	*((TUint16*) &(fileHeader.Ptr()[4])) = 0x02; 
+	*((TUint16*) &(fileHeader.Ptr()[6])) = 0x04; 
+	*((TUint32*) &(fileHeader.Ptr()[8])) = 0x00;
+	*((TUint32*) &(fileHeader.Ptr()[12])) = 0x00;
+	*((TUint32*) &(fileHeader.Ptr()[16])) = 0xffff;
+	*((TUint32*) &(fileHeader.Ptr()[20])) = 12;       // DLT_RAW		12	/* raw IP */
+	fileHeader.SetLength(fileHeader.MaxLength());
+
+	iFile.Write(fileHeader);
+	}
+
+void CProtocolProbe::LibcapDump(const TDesC8& aBuffer, TUint32 aTimeStampSecs, TUint32 aTimeStampMicros)
+//
+//  Dumps a packet in a format compatbible with Libcap
+//
+//  For each record the format is:
+//
+//  struct record 
+//      {
+//      TUint32 sec;	/* time stamp - secs*/
+//      TUint32 usec;	/* time stamp - microsecs*/
+//      TUint32 captureLen;	/* length packet captured */
+//      TUint32 packetLen;	/* total length of packet*/
+//      };
+//
+//  Byte ordering of the header is little endian
+//  Byte ordering of the packet is network byte order (big endian)
+//
+	{
+	
+	TBuf8<sizeof(TUint32)*4> recordHeader;
+	recordHeader.FillZ();
+
+	*((TUint32*) &(recordHeader.Ptr()[0])) = aTimeStampSecs;
+	*((TUint32*) &(recordHeader.Ptr()[4])) = aTimeStampMicros;
+	*((TUint32*) &(recordHeader.Ptr()[8])) = aBuffer.Length();
+	*((TUint32*) &(recordHeader.Ptr()[12])) = aBuffer.Length();
+	recordHeader.SetLength(recordHeader.MaxLength());
+
+	iFile.Write(recordHeader);
+	iFile.Write(aBuffer);
+	}
+
+
+
+TInt CProtocolProbe::DumpCb(TAny* aThisPtr)
+//
+//  Callback function - calls DumpQueuedPackets()
+//
+	{
+
+	CProtocolProbe* self = static_cast<CProtocolProbe*>(aThisPtr);
+	self->DumpQueuedPackets();
+	return KErrNone;
+	}
+
+void CProtocolProbe::DumpQueuedPackets()
+//
+//  Dumps all packets on the queue to the log file
+//
+	{
+
+	RMBufPacketBase packet;
+	while(iQueue.Remove(packet))
+		{
+		Dump(packet);
+		}
+	}