--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nettools/conntest/probe/src/prt.cpp Thu Dec 17 08:39:25 2009 +0200
@@ -0,0 +1,354 @@
+/*
+* Copyright (c) 2002-2006 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"
+
+_LIT(KTcpDumpFolder, "tcpdump\\");
+_LIT(KProbeDumpFile, "probe.cap");
+_LIT(KLogFolder, "c:\\logs\\");
+
+
+CProtocolProbe::CProtocolProbe(TUint aId) :
+iId(aId),
+iDumpCb(CActive::EPriorityStandard),
+iFileServerOpen(EFalse),
+iFileOpen(EFalse),
+iBufCreated(EFalse)
+ {
+
+ iTimeOrigin.UniversalTime();
+
+ TCallBack cbFunc(DumpCb, this);
+ iDumpCb.Set(cbFunc);
+ }
+
+void CProtocolProbe::InitL(TDesC& aTag)
+ {
+
+ CProtocolBase::InitL(aTag);
+ }
+
+void CProtocolProbe::StartL()
+ {
+ }
+
+CProtocolProbe::~CProtocolProbe()
+ {
+ 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::Identify(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;
+ anEntry.iVersion = TVersion(1, 0, 0);
+ anEntry.iByteOrder = EBigEndian;
+ anEntry.iServiceInfo = KSIDatagram | KSIConnectionLess;
+ anEntry.iNamingServices = 0;
+ anEntry.iSecurity = KSocketNoSecurity;
+ anEntry.iMessageSize = 0xffff;
+ anEntry.iServiceTypeInfo = ESocketSupport;
+ anEntry.iNumSockets = KUnlimitedSockets;
+ }
+
+void CProtocolProbe::Identify(TServerProtocolDesc *aDesc) const
+ {
+
+ Identify(*aDesc, iId);
+ }
+
+CServProviderBase* CProtocolProbe::NewSAPL(TUint aProtocol)
+ {
+
+ if (aProtocol != KSockDatagram)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ CProviderProbe* sap = new (ELeave) CProviderProbe(this);
+ sap->iNext = iList;
+ iList = sap;
+ return sap;
+ }
+
+//
+// CProtocolProbe::CancelSAP
+// *************************
+// Disconnect SAP from the protocol
+//
+void CProtocolProbe::CancelSAP(CServProviderBase *aSAP)
+ {
+
+ CProviderProbe **h, *sap;
+ for (h = &iList; (sap = *h) != NULL; h = &sap->iNext)
+ if (sap == aSAP)
+ {
+ *h = sap->iNext;
+ break;
+ }
+ }
+
+// 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)
+ {
+ iBuf.CreateL(65535);
+ iBufCreated = ETrue;
+ }
+
+ LibcapDumpFileHeader();
+ }
+
+//
+// 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)
+ {
+
+ Queue(aPacket);
+ return CProtocolPosthook::Send(aPacket, aSrc);
+ }
+
+void CProtocolProbe::Process(RMBufChain &aPacket, CProtocolBase* aSrc)
+ {
+
+ 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);
+ }
+
+void CProtocolProbe::Queue(RMBufChain &aPacket)
+//
+// Takes a copy of aPacket, adds it to the queue and triggers the callback
+//
+ {
+
+ 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;
+
+ //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
+ {
+ copy.Free();
+ }
+ }
+
+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);
+ }
+ }