linklayerutils/packetlogger/src/PacketLogger.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linklayerutils/packetlogger/src/PacketLogger.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,358 @@
+// 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:
+// Implements CPacketLogger.
+// 
+//
+
+/**
+ @file
+*/
+
+
+#include <es_sock.h>
+#include <hal.h>
+#include "PacketLogger.h"
+
+static const TInt KInternalBufferSize = 4096;
+
+/** Constants for tcpdump log*/
+static const TUint32 KTcpDumpFileHeaderMagic = 0xa1b2c3d4;
+static const TUint16 KTcpDumpVersionMajor = 2;
+static const TUint16 KTcpDumpVersionMinor = 4;
+
+/** Constants for pppdump log */
+//static const TInt8 KPppDumpRecSentData = 1;  ENABLE IF NEEDED
+//static const TInt8 KPppDumpRecRcvData = 2;   ENABLE IF NEEDED
+//static const TInt8 KPppDumpRecRcvDelim = 4;  ENABLE IF NEEDED
+static const TInt8 KPppDumpRecTimeStepLong = 5;
+static const TInt8 KPppDumpRecTimeStepShort = 6;
+static const TInt8 KPppDumpRecResetTime = 7;
+
+/**
+ * Factory method for CPacketLogger.
+ * 
+ * @param aTag The tag name for the log
+ * @param aFileName The filename to log to.
+ * @param aDumpType The type of dump (one of TDumpType values)
+ * @param aLinkType Used by tcpdump. One of the types defined in
+ * libpcap/bpf/net/bpf.h
+ * In case of ETcpDump this is *TUint32
+ * which represents the linktype as defined by TcpDump format.
+ * In case of EPppDump it is *TUint8 which represents the direction.
+ * @return Ownership of a new CPacketLogger.
+ */
+EXPORT_C CPacketLogger* CPacketLogger::NewL(const TDesC8& aTag, const TDesC8& aFileName, const TDumpType aDumpType, const TInt aLinkType)
+	{
+	CPacketLogger* self = new(ELeave)CPacketLogger;
+	CleanupStack::PushL(self);
+	self->ConstructL(aTag, aFileName, aDumpType, aLinkType);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+/**
+ * 2nd-phase construction. Creates the libpcap file. Adds the 
+ * file header based on the dump type.
+ * 
+ * @param aTag The tag name for the log
+ * @param aFileName The filename to log to.
+ * @param aDumpType The type of dump (one of TDumpType values)
+ * @param aLinkType Used by tcpdump. (Valid types are specified 
+ * in libpcap/bpf/net/bpf.h)
+ */
+#ifdef __FLOG_ACTIVE
+void CPacketLogger::ConstructL(const TDesC8& aTag, const TDesC8& aFileName, const TDumpType aDumpType, const TInt aLinkType)
+#else
+void CPacketLogger::ConstructL(const TDesC8&, const TDesC8&, const TDumpType aDumpType, const TInt aLinkType)
+#endif
+	{
+	TInt tickPeriod;
+	iPacketCounter = 0;
+	iDumpType = aDumpType;
+	//initialize the time related data
+	HAL::Get(HALData::ESystemTickPeriod, tickPeriod);
+	iTickPeriod = tickPeriod;
+	iTimeLastPacket = User::TickCount();
+	iTimeLastPacket *= iTickPeriod;
+	//initialize intermal buffer
+	iHBuf = HBufC8::NewMaxL(KInternalBufferSize);
+	//write the header
+	if(aDumpType == ETcpDump)
+		{
+		__FLOG_OPEN(aTag, aFileName);
+		WriteTcpDumpHeader(aLinkType);
+		}
+	else if(aDumpType == EPppDump)
+		{
+		__FLOG_OPEN(aTag, aFileName);
+		WritePppDumpHeader();
+		}
+	}
+	
+/**
+ * Constructor
+ */
+CPacketLogger::CPacketLogger()
+ 	{
+	}
+
+/**
+ * Destructor
+ */
+EXPORT_C CPacketLogger::~CPacketLogger()
+	{
+	delete iHBuf;
+	iHBuf = NULL;
+	
+	if(iDumpType == ETcpDump || iDumpType == EPppDump)
+		{
+		__FLOG_CLOSE;
+		}
+	}
+
+/**
+ * Adds a raw ip packet to the dump file based on the dump format.
+ * @param aPacket Packet as RMBufChain
+ * @param aDirection Direction of packet. Meaningful only in case of PPP Dump
+ */
+EXPORT_C void CPacketLogger::WritePacket(const RMBufChain& aPacket, const TUint8 aDirection)
+	{
+	TInt packetLength = aPacket.Length() - aPacket.First()->Length();
+
+	if (packetLength > KInternalBufferSize)
+		{
+		_LIT8(ERROR_STR,"Packet after packet %d was larger than 4K. It is skipped.");
+		__FLOG_1(ERROR_STR, iPacketCounter);
+		//Packet is too big for the internal buffer. Don't dump it.
+		return;
+		}
+		
+	TPtr8 packetPtr = iHBuf->Des();
+	packetPtr.SetLength(packetLength);
+	aPacket.CopyOut(packetPtr, aPacket.First()->Length());
+	
+	WritePacket(packetPtr, aDirection);
+	}
+
+/**
+ * Adds a text log to the log file.
+ * @param aText text to be added
+ */
+EXPORT_C void CPacketLogger::WriteText(const TDesC8& aText)
+	{
+	__FLOG_0(aText);
+	}
+
+/**
+ * Adds a raw ip packet to the dump file based on the dump format.
+ * @param aPacket Packet as buffer
+ * @param aDirection Direction of packet. Meaningful only in case of PPP Dump
+ */
+EXPORT_C void CPacketLogger::WritePacket(const TDesC8& aPacket, const TUint8 aDirection)
+	{
+	iPacketCounter++;
+	if(iDumpType == ETcpDump)
+		{
+		TcpDumpPacket(aPacket);
+		}
+	else if(iDumpType == EPppDump)
+		{
+		PppDumpPacket(aPacket, aDirection);
+		}
+	}
+	
+/**
+ * Dumps file header in a format compatible with Libcap.
+ * Libcap compatible files can be manipulated via
+ * utilities such as Mergecap (http://www.ethereal.com/docs/man-pages/mergecap.1.html)
+ * Ethereal (http://www.ethereal.com/docs/man-pages/ethereal.1.html)
+ * etc. More information can be found from www.ethereal.com
+ * tcpdump file header format is as follows
+ * @code
+ * struct TFileHeader 
+ * 	{
+ * 	TUint32 magic; 
+ * 	TUint16 version_major;
+ * 	TUint16 version_minor;
+ * 	TInt32  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 specified in libpcap/bpf/net/bpf.h) 
+ * 						// 12 corresponds to raw IP
+ * 	};
+ * @endcode
+ * @param aLinkType Link type for the packet (One of the types specified in
+ * libpcap/bpf/net/bpf.h)
+ */
+void CPacketLogger::WriteTcpDumpHeader(const TInt aLinkType)
+	{
+	//construct the file header
+  	TBuf8<sizeof(TUint32)*5+sizeof(TUint16)*2> fileHeader;
+  	fileHeader.SetLength(fileHeader.MaxLength());
+  	
+	BigEndian::Put32(&fileHeader[0], KTcpDumpFileHeaderMagic);
+	BigEndian::Put16(&fileHeader[4], KTcpDumpVersionMajor);
+	BigEndian::Put16(&fileHeader[6], KTcpDumpVersionMinor);
+	BigEndian::Put32(&fileHeader[8], 0); //gmt to local correction
+	BigEndian::Put32(&fileHeader[12], 0); //accuracy of timestamps
+	BigEndian::Put32(&fileHeader[16], 0xffff); //max length saved portion of each packet
+	BigEndian::Put32(&fileHeader[20], static_cast<TUint32>(aLinkType));
+	
+	//write the file header
+	__FLOG_BINARY(fileHeader);
+	}
+
+/**
+ * Adds a raw ip packet to the dump file based on tcpdump format.
+ * @param aPacket TCP packet to dump
+ * tcpdump packet header format is as follows
+ * @code
+ * struct TTimeval 
+ * 	{
+ * 	TUint32 tv_sec;     // seconds
+ * 	TUint32 tv_usec;    // microseconds
+ * 	};
+ * struct TPacketHeader 
+ * 	{
+ * 	TTimeval ts;		// time stamp
+ * 	TUint32  caplen;	// length of portion present
+ * 	TUint32  len;		// length of this packet (off wire)
+ * 	};
+ * @endcode
+ */
+void CPacketLogger::TcpDumpPacket(const TDesC8& aPacket)
+	{
+	TInt32 nsecs;
+	TInt32 secs;
+	TInt64 curTime = User::TickCount();
+	curTime *= iTickPeriod;
+	
+	//seconds portion of offset
+	TInt64 timeInSeconds = curTime / 1000000;
+	//microsends portion of offset
+	TInt64 timeInNSeconds;
+	I64DIVMOD(curTime, 1000000, timeInNSeconds);
+	
+	secs = I64INT(timeInSeconds);
+	nsecs = I64INT(timeInNSeconds);
+	iTimeLastPacket = curTime;
+	
+	//construct the packet header
+  	TBuf8<sizeof(TUint32)*4> packetHeader;
+  	packetHeader.SetLength(packetHeader.MaxLength());
+
+	BigEndian::Put32(&packetHeader[0], secs); //seconds for time stamp
+	BigEndian::Put32(&packetHeader[4], nsecs); //microseconds for time stamp
+	BigEndian::Put32(&packetHeader[8], aPacket.Length()); //length of portion present
+	BigEndian::Put32(&packetHeader[12], aPacket.Length()); //length of this packet
+  	
+	//dump the packet header
+	__FLOG_BINARY(packetHeader);
+
+	//dump the packet
+	__FLOG_BINARY(aPacket);
+	}
+
+/**
+ * Dumps file header in a format compatible with pppdump.
+ * As a file header just drop a 0x07|t3|t2|t1|t0 record followed by a
+ * 0x05|t3|t2|t1|t0 record, that seems common practice.
+ * Since this "header" is actually a regular record, it can be
+ * appended to an existing file.
+ */
+void CPacketLogger::WritePppDumpHeader()
+	{
+	_LIT(Ktime_tOrigin,"19700000:000000.000000");
+	TTime time_t_Origin(Ktime_tOrigin);
+	TTimeIntervalSeconds secs;
+	TTime timeNow;
+	timeNow.UniversalTime();
+	timeNow.SecondsFrom(time_t_Origin,secs);
+	
+	TBuf8<10> fileHeader;
+	fileHeader.SetLength(fileHeader.MaxLength());
+	
+	fileHeader[0] = KPppDumpRecResetTime;
+	BigEndian::Put32(&fileHeader[1], secs.Int());
+
+	fileHeader[5] = KPppDumpRecTimeStepLong;
+	BigEndian::Put32(&fileHeader[6], 0);
+	
+	//dump the file header
+	__FLOG_BINARY(fileHeader);
+	}
+
+/**
+ * Dumps a packet in a pppdump format (see www.ethereal.com)
+ * @param aPacket Raw IP packet to dump
+ * For each record the format is:
+ * @code
+ * 0x07|t3|t2|t1|t0	Reset time    t = time_t (UNIX: secs since 01/01/1970)
+ * 0x06|t0			Time step (short) - ts = time step (tenths)
+ * 0x05|t3|t2|t1|t0	Time step (short) - ts = time step (tenths)
+ * 0x04			Receive deliminator (not seen in practice)
+ * 0x02|n1|n0		Received data	- n = number of bytes following
+ * 0x01|n1|n0		Sent data		- n = number of bytes following
+ * @endcode
+ * Byte ordering of the header is little endian
+ * Byte ordering of the packet is network byte order (big endian)
+ * 
+ * @param aPacket PPP packet as buffer
+ * @param aDirection Direction of packet.
+ */
+void CPacketLogger::PppDumpPacket(const TDesC8& aPacket, const TUint8 aDirection)
+	{
+	TInt64 curTime = User::TickCount();
+	curTime *= iTickPeriod;
+	//offset in microseconds
+	TInt64 timeOffset = curTime - iTimeLastPacket;
+	//seconds portion of offset
+	TInt64 timeInTenthOfSeconds = timeOffset / 100000;
+	TUint32 timeStep = I64INT(timeInTenthOfSeconds);
+	
+	if(timeStep)
+		{
+		iTimeLastPacket = curTime;
+		}
+	
+	TBuf8<2+6> recordHeader;
+	int i=0;
+	if (timeStep > 0xff)
+		{
+		// 32-bit differential time record
+		recordHeader.SetLength(8);
+		recordHeader[i++] = KPppDumpRecTimeStepLong;
+		BigEndian::Put32(&recordHeader[i], timeStep);
+		i += 4;
+		}
+	else if (timeStep > 0)
+		{
+		// 8-bit differential time record
+		recordHeader.SetLength(5);
+		recordHeader[i++] = KPppDumpRecTimeStepShort;
+		recordHeader[i++] = (TUint8) timeStep;
+		}
+	else
+		{
+		recordHeader.SetLength(3);
+		}
+	recordHeader[i++] = aDirection;
+	BigEndian::Put16(&recordHeader[i], (TUint16)aPacket.Length());
+	
+	//dump the packet header
+	__FLOG_BINARY(recordHeader);
+	
+	//dump the packet
+	__FLOG_BINARY(aPacket);
+	}