commands/ping/pingmodel.cpp
changeset 0 7f656887cf89
child 86 56b6ee983610
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/ping/pingmodel.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,1255 @@
+// Copyright (c) 2000-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:
+// Accenture - minor mods to work as an fshell command and fixes to broken logic
+//
+// Description:
+// pingmodel.cpp - icmp echo client engine
+// This software has been implemented in the 6PACK
+// project at the Mobile Networks Laboratory (MNW)
+// http://www.research.nokia.com/projects/6pack/
+// REMARKS:
+// The application is prepared to admit the option Hop Limit and
+// Numeric output (no name resolution), but these options are not used
+// because the socket is open in ICMP mode.  To use them need an IP
+// socket and IP packets to set the options. Some code is commented and
+// can be used in case of need
+//
+
+
+
+#ifdef IAPSETTING
+#include <commdb.h>
+#endif
+
+#include <e32math.h>
+#include <e32std.h>
+//#include <eikenv.h>
+//#include <netdial.h>
+
+// IPv6 changes CPing::iType, ComposeFirstIcmpPacket()- ICMPType, Socket Open()
+
+#include "pingmodel.h"
+
+//#include <pingapp.rsg> //resource is not needed as console app
+
+#include "ping_misc.h"
+
+
+CPing::CPing():CActive(EPriorityStandard),iPacket(0,0),iReceivedData(0,0)
+{
+	CActiveScheduler::Add(this);	//Adds itself to the scheduler only the first time
+}
+
+
+
+//Sets all default values. Actually it's no more a L function
+void CPing::ConstructL(TPreferences aPref)
+{
+
+	// Base class second-phase construction.
+
+	//iHostname=_L("bart.research.nokia.com");	//default initial addr
+	//iHostname=_L("127.0.0.1");	//default initial addr
+	//iHostname=_L("dead::beef");	//default initial addr
+	iHostname=aPref.iHostname;
+	iPackLimit = aPref.iFlags & KPingPackLimit;		//Unlimited packets
+	iTotalPackets=aPref.iTotalPackets;	//Default packet number when limited number
+	
+	iSecWait=aPref.iSecWait;		//Default 1 second
+	iPacketDataSize=aPref.iPacketDataSize;	//Default Size
+	iQuiet=aPref.iFlags & KPingQuiet;	//No packet info, just statistics
+		
+	iVerbose=aPref.iFlags & KPingVerbose;	//Verbose Output. All ICMP packets, not only Echo reply. Default no
+	iPattern.Copy(aPref.iPattern);			//Pattern 0xFF (1-filled byte)
+	
+	iDebug=aPref.iFlags & KPingDebug;		//Set SO_DEBUG flag
+	iLastSecWait=aPref.iLastSecWait;	//Default time to wait for the last packet
+
+#ifdef IAPSETTING
+	iIAP = aPref.iIAP;		
+#endif
+
+	//Not used by now
+	iNumericOutput=EFalse;	//Resolve adresses by default
+	iHopLimit=0;			//Time-to-live in hops default 255 ( 1 to 255) (0 means not set)
+
+	iDupPackets=0;			//Duplicated packets
+	iRunning=EFalse;		// Tells if there's an Instance of Ping Running
+
+
+	
+/*
+	iReceivedDataBuffer= HBufC8::NewL(iPacketDataSize + ICMP_ECHO_HEADER_SIZE);	//Maximum size of a return packet
+	TPtr8 auxPtr(iReceivedDataBuffer->Des());	//must be used here because the buffer changes
+	iReceivedData.Set(auxPtr);			//we use an aux var because can't use Des() directly Why??
+*/
+}
+
+//return the current preferences
+void CPing::GetPreferences(TPreferences &aPref)
+{	
+	aPref.iFlags=0;
+	if (iQuiet)
+		aPref.iFlags|=KPingQuiet;
+	if (iVerbose)
+		aPref.iFlags|=KPingVerbose;
+	if (iPackLimit)
+		aPref.iFlags|=KPingPackLimit;
+	if (iDebug)
+		aPref.iFlags|=KPingDebug;
+
+	aPref.iSecWait=iSecWait;               //Time between sent packets (Default 1 second)
+	aPref.iPacketDataSize=iPacketDataSize;//Default Data Size (not including ICMP header)
+	aPref.iTotalPackets=iTotalPackets;  //Number of ICMP Echo Request packets to send
+	aPref.iLastSecWait=iLastSecWait;   //Time to wait for the Last packet. Default 2
+	aPref.iHostname=iHostname;		//Address to Ping
+	aPref.iPattern.Copy(iPattern);
+
+#ifdef IAPSETTING	
+	aPref.iIAP = iIAP;
+#endif
+		
+}
+
+void CPing::DefaultPreferences(TPreferences &aPref)
+{	
+	aPref.iFlags=KPingVerbose|KPingPackLimit;
+
+	aPref.iSecWait=1;               //Time between sent packets (Default 1 second)
+	aPref.iPacketDataSize=56;//Default Data Size (not including ICMP header)
+	aPref.iTotalPackets=5;  //Number of ICMP Echo Request packets to send
+	aPref.iLastSecWait=2;   //Time to wait for the Last packet. Default 2
+	aPref.iPattern=_L("FF");
+	aPref.iHostname=_L("127.0.0.1");
+#ifdef IAPSETTING
+	aPref.iIAP=1;
+#endif
+}
+
+void CPing::Statistics()
+{
+	//TBuf<300> aux(_L("==========================================\n"));
+	TBuf<300> aux(_L("\n"));
+	
+	TReal rLoss=iSentPackets-iRecvPackets-iChksumErrors;	// An error is a received but wrong packet
+										//is not masked as received because of time calculations
+	if (rLoss<0) 
+		rLoss=0;
+	TReal rSent=iSentPackets;
+	TReal r;
+	if (rSent>0)
+		r=rLoss/rSent;
+	else
+		r=0;
+
+	aux.AppendFormat(_L("Lost: %.1f%% Bad: %d"), r*100, iChksumErrors);
+
+	//If there's a timestamp and data received
+	if ((iRecvPackets>0) && (iPacketDataSize >= TIMESTAMP_SIZE))
+	{
+		r=(iTimeSum/iRecvPackets);	//average in ms
+		aux.AppendFormat(_L(" Max: %d Min: %d Avg: "),iMaxTime,iMinTime);
+		TRealFormat format;	//no decimals
+		format.iType|=KDoNotUseTriads;	// no thousands separatorlast
+		aux.AppendNum(r,format);
+		aux.Append(_L(" ms"));
+	}
+
+	if (iDupPackets>0)
+		aux.AppendFormat(_L(" Dup: %d"),iDupPackets);
+
+	//aux.Append(_L("\n==========================================\n"));
+	iConsole->WriteLine(aux);
+}
+
+// Use when data is not going to be displayed in Quiet mode
+void CPing::WriteLineIfNotQuiet(const TDesC& abuf)
+{
+	if (!iQuiet)
+		iConsole->WriteLine(abuf);
+}
+
+TDes* CPing::GetHostName()
+{
+	return &iHostname;
+}
+
+void CPing::SetHostName(const TDesC& ahostname)
+{
+	iHostname=ahostname;
+}
+
+void CPing::SetConsole(CPingContainer* aConsole)
+{
+	iConsole=aConsole;
+}
+
+CPing::~CPing()
+	{
+	Cancel();
+	delete iPacketData;		// If something leaves.
+	delete iReceivedDataBuffer;
+	CloseAll();
+	}
+
+//Shows the error and set the application as not running. 
+//Requires a return after calling it!
+void CPing::ErrorL(const TDesC& string,TInt error)
+{
+	
+	TBuf<150> aux;
+	TBuf<100> errtxt;
+
+	//CEikonEnv::Static()->GetErrorText( errtxt,error);
+	aux.Format(string);	
+	aux.Append(_L(": "));
+	aux.Append(errtxt);
+	aux.AppendFormat(_L(" (%d)\n"), error);
+	WriteLineIfNotQuiet(aux);
+	//iRunning=EFalse;
+
+	iSockErrors++;
+
+	if (error==KErrAbort)	//Critical Error
+	{
+
+/*		RNetDial xnetdial;
+		TBool active;
+
+		xnetdial.Open();
+		TInt err=xnetdial.NetworkActive(active);
+	
+		if (!active)
+		{
+			xnetdial.Start();
+			err=xnetdial.NetworkActive(active);
+		}
+*/
+		EndPingL();
+		User::Leave(0);	// NOT SURE IF IT'S THE BEST WAY!!!
+	}
+
+	if (iSockErrors>5)	//To avoid a chain of errors that blocks everything. Should never happen though 
+	{
+		EndPingL();
+		User::Leave(0);	// NOT SURE IF IT'S THE BEST WAY!!!
+	}
+	
+}
+
+
+// checksum of the ICMP packet (ICMP header + data)
+TUint16 CPing::in_chksum(TUint16* data, TUint len)
+{
+	
+	TUint16 *d=data;
+	TUint left=len;
+	TUint32 sum=0;
+	TUint16 aux=0;
+	
+	while (left > 1)
+	{
+		sum += *d++;
+		left -= 2;		//because adding 16 bits numbers (2 bytes)
+	}
+
+	if (left==1)	//If odd length
+	{
+		*(TUint8*) &aux = *(TUint8*) d;
+		sum += aux;
+	}
+	
+	sum = (sum >> 16) + (sum & 0x0ffff);
+	sum += (sum >> 16);
+	aux = (TUint16) ~sum;
+
+	return aux;
+	
+}
+
+// Clears a bit from the iDup table
+
+void CPing::CLR(TUint16 num)
+{
+	TInt num256 = num % 256;		//num modulus 256
+	TInt pos = num256 >> 5;		//Position of vector iDup
+	iDup[pos] &= ~((1 << num % 32 ));
+}
+
+// Sets a bit from the iDup table
+
+void CPing::SET(TUint16 num)
+{
+	TInt num256= num % 256;		//num modulus 256
+	TInt pos=num256 >> 5;		//Position of vector iDup
+	iDup[pos] |= (1 << num % 32 );
+}
+
+// Tests if the bit is set or not
+
+TBool CPing::TEST(TUint16 num)
+{
+	TUint num256= num % 256;		//num modulus 256
+	TInt pos=num256 >> 5;		//Position of vector iDup
+	return ((iDup[pos] & (1 << num % 32)) == (TUint32)(1 << num % 32));
+}
+
+//Generates a random number using iSeed
+TUint16 CPing::RandomNumber()
+{
+	if (iSeed==0)	//Initialize seed randomly with time
+	{
+		TTime time;
+        time.HomeTime();
+		iSeed=time.Int64();
+    }
+    return ((TUint16)Math::Rand(iSeed));	//Just take the lowest 16 bits)
+}
+
+// Composes the whole ICMP packet except time stamp and checksum
+
+void CPing::ComposeFirstICMPPacket()
+{
+	ThdrICMP *hdr;
+	TUint firstPos = 0;
+	
+	hdr = (ThdrICMP *)&iPacket[0];	// Can use this one for IPv6 because is the same format
+
+	if (iType == IPv4)
+		hdr->NetSetType(KICMPTypeEchoRequest);
+	else
+		hdr->NetSetType(KInet6ICMP_EchoRequest);
+
+	hdr->NetSetCode(KICMPCode);
+
+	iId = RandomNumber();
+	((ThdrICMP_Echo *)hdr)->NetSetId(iId);	
+	((ThdrICMP_Echo *)hdr)->NetSetSeq(0);
+	CLR(0);	// Clears the bit in the received/dup buffer
+	
+	// Jump over possible timestamp
+
+	if (iPacketDataSize >= TIMESTAMP_SIZE)
+	{
+		firstPos = TIMESTAMP_SIZE;
+	}
+
+	// The rest is filled with a pattern
+	// The last part of the packet may only be a part of the pattern
+
+	TInt i;
+	TInt j;
+
+	//First transform the pattern from text to Hexadecimal
+	TLex lex;
+	//TUint8 hex_num;
+	TBuf<2> hex_digit;
+	TBuf<2 * MAX_PATTERN_LENGTH> text_pattern;
+	TUint8 hex_pattern[MAX_PATTERN_LENGTH];
+	if (iPattern.Length() % 2 == 0)
+		text_pattern.Copy(iPattern);
+	else	//odd size so the pattern is doubled and we have a even size
+	{
+		text_pattern.Copy(iPattern);
+		text_pattern.Append(iPattern);
+	}
+
+	for (i = 0; i < text_pattern.Length(); i += 2)
+	{
+		hex_digit.Copy(text_pattern.Ptr() + i, 2);	//Copy 2 text digits 1 byte
+		lex.Assign(hex_digit);
+		lex.Val(hex_pattern[i/2], EHex);		//Can't fail because only 2 digits
+		//hex_pattern.Append((TUint8 *)&hex_num, sizeof(TUint8));	//Append the hex digit (byte)
+	}
+
+
+	
+	for (j = 0, i = firstPos; (TUint)i < iPacketDataSize; i++, j++)
+	{
+		iPacket[ICMP_ECHO_HEADER_SIZE + i] = !text_pattern.Length()
+			? (TUint8)(i % 256)
+			: hex_pattern[j % (text_pattern.Length()/2)];	//hex_pattern is half the size of text pattern
+	}
+//	TBuf8<150> prova;
+//	prova.Copy(iPacket);
+	StampPacket();
+}
+
+// Only composes timestamp and sequence number and calculates checksum
+
+void CPing::ComposeICMPPacket()
+{
+	ThdrICMP *hdr = (ThdrICMP *)&iPacket[0];
+	TUint16 seq = (TUint16)(((ThdrICMP_Echo *)hdr)->NetGetSeq() + 1);
+
+	((ThdrICMP_Echo *)hdr)->NetSetSeq(seq);	// Next seq. Number
+	CLR(seq);	// Clears the bit in the received/dup buffer
+
+	StampPacket();
+}
+
+void CPing::StampPacket()
+{
+	ThdrICMP *hdr = (ThdrICMP *)&iPacket[0];
+
+	if (iPacketDataSize >= TIMESTAMP_SIZE)
+	{
+		TTime time;
+		time.UniversalTime();
+		*(TInt64*)&iPacket[8] = time.Int64();	// Converts the time to a Int64 value
+	}
+
+	hdr->NetSetChecksum(0);
+	hdr->NetSetChecksum(in_chksum((TUint16 *)&iPacket[0], iPacketDataSize + ICMP_ECHO_HEADER_SIZE));
+}
+
+//Puts the next seq number in the packet (iPacket)
+void CPing::NextSeq()
+{
+	ThdrICMP_Echo *hdr;
+
+	hdr=(ThdrICMP_Echo *)&iPacket[8];
+	hdr->SetSeq((TUint16)((hdr->NetGetSeq()) + 1));
+}
+
+//TPtrC CPing::PacketTypev6(TInet6HeaderICMP_Echo *aHdr)
+void CPing::PacketTypev6(TDes& buf,ThdrICMP *aHdr)
+{
+	//TBuf<40> buf;
+	TInet6HeaderICMP *hdr = (TInet6HeaderICMP *)aHdr;
+	//TInet6HeaderICMP_Echo *echoHdr;
+
+	TInt8 code=hdr->Code();
+	switch(hdr->Type())
+	{
+		//Errors 0-127
+		case KInet6ICMP_Unreachable: 
+			//buf.Format(_L("type= "));
+			buf.Append(_L("Dest. Unreachable: "));
+			//buf.Format(_L("type=%d "),type);
+			switch (code)
+			{
+			case KInet6ICMP_NoRoute:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("No Route "));
+				break;
+			case KInet6ICMP_AdminProhibition:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Admin. Prohibition "));
+				break;
+			case KInet6ICMP_NotNeighbour:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Not a Neighbour "));
+				break;
+			case KInet6ICMP_AddrUnreach:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Addr. Unreachable "));
+				break;
+			case KInet6ICMP_PortUnreach:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Port Unreachable "));
+				break;
+			default: buf.AppendFormat(_L("code=%d "),code);
+			}
+			break;
+		case KInet6ICMP_PacketTooBig:
+			//buf.Format(_L("type= "));
+			buf.Append(_L("Pack. Too big "));
+			break;
+		case KInet6ICMP_TimeExceeded:
+			//buf.Format(_L("type= "));
+			buf.Append(_L("Time exceeded: "));
+			switch (code)
+			{
+			case KInet6ICMP_HopLimitExceeded:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Hop Limit "));
+				break;
+			case KInet6ICMP_FragReassExceeded:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Frag. Reassembly "));
+				break;
+			default: buf.AppendFormat(_L("code=%d "),code);
+			}
+			break;
+		case KInet6ICMP_ParameterProblem:
+			//buf.Format(_L("type= "));
+			buf.Append(_L("Parameter problem: "));
+			switch (code)
+			{
+			case KInet6ICMP_ErrHdrField:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Bad header filed"));
+				break;
+			case KInet6ICMP_NextHdrUnknown:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Unknown Next Header "));
+				break;
+			case KInet6ICMP_OptionUnkown:
+				//buf.Append(_L("code= "));
+				buf.Append(_L("Unknown Option"));
+				break;
+			default: buf.AppendFormat(_L("code=%d "),code);
+			}
+			break;
+
+		//Information 128-255
+		case KInet6ICMP_EchoRequest:
+			//echoHdr=(TInet6HeaderICMP_Echo *)hdr;
+			buf.Append(_L("Echo Request "));
+			//buf.AppendFormat(_L("id= %d "),echoHdr->Identifier());
+			//buf.AppendFormat(_L("Seq= %d "),echoHdr->Sequence());
+			break;
+		case KInet6ICMP_EchoReply:
+			//echoHdr=(TInet6HeaderICMP_Echo *)hdr;
+			buf.Append(_L("Echo Reply "));
+			//buf.AppendFormat(_L("id= %d "),echoHdr->Identifier());
+			//buf.AppendFormat(_L("Seq= %d "),echoHdr->Sequence());
+			break;
+	
+		case KInet6ICMP_Redirect:
+ 			buf.Append(_L("Redirect "));
+			break;
+
+		case KICMPTypeRouterAdvert: 
+		case KInet6ICMP_RouterAdv:
+			buf.Append(_L("Router advertisement "));
+			break;
+
+		case KICMPTypeRouterSolicit: 
+		case KInet6ICMP_RouterSol:
+			buf.Append(_L("Router solicitation "));
+			break;
+
+		case KInet6ICMP_GroupQuery:
+			buf.Append(_L("KInet6ICMP_GroupQuery "));
+			break;
+
+		case KInet6ICMP_GroupReport:
+			buf.Append(_L("KInet6ICMP_GroupReport "));
+			break;
+
+		case KInet6ICMP_GroupDone:
+			buf.Append(_L("KInet6ICMP_GroupDone "));
+			break;
+
+		case KInet6ICMP_NeighborSol:
+			buf.Append(_L("Neighbor Solicitation "));
+			break;
+
+		case KInet6ICMP_NeighborAdv:
+			buf.Append(_L("Neighbor Advertisement "));
+			break;
+
+		default: //buf.Format(_L("Unknown ICMP Type"));
+			buf.Format(_L("Unknown ICMP Type"));
+			//buf.Format(_L("type=%d "),hdr->Type());
+	}
+	//buf.Append(_L("\n"));
+
+}
+
+TPtrC CPing::PacketType(ThdrICMP *aHdr)
+{
+	switch(aHdr->NetGetType())
+	{
+		case KICMPTypeEchoReply: return _L("ICMP Echo reply");
+		case KICMPTypeUnreachable: 
+			switch (aHdr->NetGetCode())
+			{
+				case KICMPCodeUnreachNet: return _L("Network Unreachable");
+				case KICMPCodeUnreachHost: return _L("Host Unreachable");
+				case KICMPCodeUnreachProtocol: return _L("Protocol Unreachable");
+				case KICMPCodeUnreachPort: return _L("Port Unreachable");
+				case KICMPCodeUnreachNeedFrag: return _L("Message too long. Fragmentation needed");
+				case KICMPCodeUnreachSrcRouteFail: return _L("Source Route Failed");
+				case KICMPCodeUnreachNetUnknown: return _L("Destination Network Unknown");
+				case KICMPCodeUnreachHostUnknown: return _L("Destination Host Unknown");
+				case KICMPCodeUnreachSrcHostIsolated: return _L("Source host isolated");
+				case KICMPCodeUnreachNetProhibited: return _L("Destination Network Administatively prohibited");
+				case KICMPCodeUnreachHostProhibited: return _L("Destination Host Administatively prohibited");
+				case KICMPCodeUnreachNetTOS: return _L("Network Unreachable for TOS");
+				case KICMPCodeUnreachHostTOS: return _L("Host Unreachable for TOS");
+				case KICMPCodeUnreachProhibited: return _L("Communication Administatively prohibited");
+				case KICMPCodeUnreachPrecVolation: return _L("Host Precedence violation");
+				case KICMPCodeUnreachPrecCutoff: return _L("Precedence cutoff in effect");
+				default: return _L("Unknown code for Destination Unreachable");
+			}
+		case KICMPTypeSourceQuench: return _L("Source Quench");
+		case KICMPTypeRedirect: 
+			switch (aHdr->NetGetCode())
+			{
+				case KICMPCodeRedirectNet: return _L("Redirect for network");
+				case KICMPCodeRedirectHost: return _L("Redirect for Host");
+				case KICMPCodeRedirectNetTOS: return _L("Redirect for TOS and Network");
+				case KICMPCodeRedirectHostTOS: return _L("Redirect for TOS and Host");
+				default: return _L("Unknown code for ICMP Redirect");
+			}
+		case KICMPTypeEchoRequest: return _L("Echo Request");
+		case KICMPTypeRouterAdvert: return _L("Router advertisement");
+		case KICMPTypeRouterSolicit: return _L("Router solicitation");
+		case KICMPTypeTimeExceeded: 
+			switch (aHdr->NetGetCode())
+			{
+				case KICMPCodeExceedInTransit: return _L("TTL 0 during Transit");
+				case KICMPCodeExceedInReasm: return _L("TTL 0 during Reassembly");
+				default: return _L("Unknown Code for Time exceeded type");
+			}
+		case KICMPTypeBadParameter: return _L("Parameter Problem");
+		case KICMPTypeTimeRequest: return _L("Timestamp Request");
+		case KICMPTypeTimeReply: return _L("Timestamp Reply");
+		case KICMPTypeInfoRequest: return _L("Information Request");
+		case KICMPTypeInfoReply: return _L("Information Reply");
+		case KICMPTypeMaskRequest: return _L("Adress Mask Request");
+		case KICMPTypeMaskReply: return _L("Adress Mask Reply");
+		default: return _L("Unknown ICMP Type");
+	}
+}
+
+// Shows ICMP data in the Packet and calculates time related info
+
+void CPing::PrintICMPData(const TDesC8& data)
+{
+	TBuf<300> aux;
+	ThdrICMP *hdr;	// Use only this one because the packet format for ICMP_Echo_reply is 
+					// identical in both ICMPv4 and ICMPv6
+
+	hdr=(ThdrICMP*)&data[0];	// ICMP packet format
+
+	TUint type;
+	if (iType==IPv4)
+		type=KICMPTypeEchoReply;
+	else	// ICMPv6
+		type=KInet6ICMP_EchoReply;
+
+	if (hdr->NetGetType()!=type)
+	{
+		// We want to list other packets than ICMP Echo Reply
+		if (iVerbose)
+		{
+			if (iType==IPv4)
+				aux.Format(PacketType(hdr)); // Return a description of the packet Type and Code
+			else
+			{
+				TBuf<40> auxBuf;
+				PacketTypev6(auxBuf,hdr);
+				aux.Format(auxBuf);	// Return a description of the packet Type and Code
+			}
+			aux.Append(_L("\n"));
+			WriteLineIfNotQuiet(aux);
+		}	// else we ignore them
+		return;
+	}
+	
+	// Checks if it's a the packet have a correct Id
+	// Useful if two instances if Ping running (not possible in this version)
+
+	if (((ThdrICMP_Echo *)hdr)->NetGetId()!=iId)
+	{
+		aux.Append(_L("Packet with wrong id received\n"));
+		WriteLineIfNotQuiet(aux);
+		return;
+	}
+
+	// Correct packet type and code
+
+	aux.AppendFormat(_L("Seq: %u"),((ThdrICMP_Echo *)hdr)->NetGetSeq());
+
+	// Checks if chksum is correct must be 0 (because includes the checksum field)
+	// else there's something wrong
+
+	if (iType==IPv4)
+	{
+		if (in_chksum((TUint16 *)&data[0], iPacketDataSize + ICMP_ECHO_HEADER_SIZE)!=0)
+		{
+			aux.Append(_L(" Checksum Error\n"));
+			WriteLineIfNotQuiet(aux);
+			iChksumErrors++;
+			return;
+		}
+	}
+	// ICMPv6 checks checksum internally
+
+	// Timestamp calculation
+
+	if (iPacketDataSize >= TIMESTAMP_SIZE)
+	{
+		TTime now;
+		TTime time(*(TInt64*)&data[8]);
+		now.UniversalTime();
+
+		TTimeIntervalMicroSeconds interval;
+		interval = now.MicroSecondsFrom(time);
+#ifdef I64LOW
+		TUint num = I64LOW(interval.Int64()) / 1000;
+#else
+		TUint num = interval.Int64().GetTInt() / 1000;
+#endif
+
+		if (num > iMaxTime)
+			iMaxTime = num;
+
+		if (num < iMinTime)
+			iMinTime = num;
+
+		iTimeSum += num;
+
+		aux.AppendFormat(_L("\tTime: %d ms"),num);
+	}
+	
+	iRecvPackets++;
+
+	// Test if duplicated
+
+	if (TEST(((ThdrICMP_Echo *)hdr)->NetGetSeq()))
+	{
+		aux.Append(_L("\tDUPLICATED"));
+		iRecvPackets--;	// because duplicated
+		iDupPackets++;  // to show it in statistics
+	}
+	else
+	{
+		SET(((ThdrICMP_Echo *)hdr)->NetGetSeq());	// Marks the packet as received
+	}
+
+	//aux.Append(_L("\n"));
+	WriteLineIfNotQuiet(aux);
+}
+
+void CPing::Stop()
+{
+	iRunning=EFalse;
+	iConsole->OnEnd();
+
+	//CEikonEnv::Static()->BusyMsgCancel();
+	/*
+	delete iPacketData;
+	iPacketData=NULL;
+	delete iReceivedDataBuffer;
+	iReceivedDataBuffer=NULL;
+	*/
+}
+
+void CPing::BeginL()
+{
+	TInt err=0;
+
+	if (IsRunning())	// There's another instance running
+		return;
+	else
+		iRunning=ETrue;
+
+	//INITIALIZATION
+	iSentPackets=0;		//ICMP Echo Request Packets sent
+	iRecvPackets=0;		//ICMP Echo Reply Packets received
+	iChksumErrors=0;	//Packets with errors when checking checksum
+	iSockErrors=0;		//Errors when writing/reading to/from the sockets
+	iDupPackets=0;		//Duplicated packets
+
+	iMaxTime=0;			//Time-related vars
+	iMinTime=KMaxTUint32;
+	iTimeSum=0;
+
+	if (iPacketDataSize > MAX_ICMP_PACKETSIZE)  //Is prevented in .rss file
+		iPacketDataSize = MAX_ICMP_PACKETSIZE;
+
+	
+	delete iPacketData;
+	iPacketData= HBufC8::NewL(iPacketDataSize + ICMP_HDRLEN); 
+						//Allocates space for the ICMP packet
+	TPtr8 aux(iPacketData->Des());	//weird but necessary. Cannot use Des() directly in iPacket
+	iPacket.Set(aux);
+	//iPacket.SetMax();	//because it'll be written directly using [] in Compose...() and it would crash.
+	//HUOM!!! Cannot be SetMax because sometimes the reserved size is slightly bigger. Because of block size?
+	iPacket.SetLength(iPacketDataSize + ICMP_HDRLEN);	//because it'll be written directly using [] in Compose...() and it would crash.
+
+
+	delete iReceivedDataBuffer;
+	iReceivedDataBuffer= HBufC8::NewL(iPacketDataSize + ICMP_ECHO_HEADER_SIZE);	//Maximum size of a return packet
+	TPtr8 auxPtr(iReceivedDataBuffer->Des());	//must be used here because the buffer changes
+	iReceivedData.Set(auxPtr);			//we use an aux var because can't use Des() directly Why??
+	
+	iConsole->WriteHostL(iHostname);
+	iConsole->WriteLine(_L("Connecting...\n"));	
+	iConsole->UpdateStatisticsL();
+	
+	
+#ifdef IAPSETTING
+	//CStoreableOverrideSettings *settings = NULL;
+	//CCommDbOverrideSettings::TParamList ParamList = CCommDbOverrideSettings::TParamList::EParamListPartial;
+	//CCommDbOverrideSettings::TParamList ParamList = CCommDbOverrideSettings::TParamList::EParamListPartial;
+	TCommDbDatabaseType Type = EDatabaseTypeIAP;
+	CStoreableOverrideSettings *settings = CStoreableOverrideSettings::NewL(CCommDbOverrideSettings::EParamListPartial,Type);
+	
+	CleanupStack::PushL(settings);
+	
+	CCommsDbConnectionPrefTableView::TCommDbIapConnectionPref conPref;
+	conPref.iRanking = 1;
+	conPref.iDirection = ECommDbConnectionDirectionOutgoing;
+	CCommsDbConnectionPrefTableView::TCommDbIapBearer bearer;
+	bearer.iIapId = iIAP;
+	conPref.iBearer = bearer;
+
+	err = settings->SetConnectionPreferenceOverride(conPref);
+	User::LeaveIfError(err);
+	User::LeaveIfError(iGenericAgent.Open());
+    iGenericAgent.StartOutgoing(*settings,iStatus);
+	
+	err = iGenericAgent.DisableTimers();
+    if (err != KErrAlreadyExists)
+        User::LeaveIfError(err);
+	CleanupStack::PopAndDestroy();	
+	User::WaitForAnyRequest();
+#endif
+
+
+	//connecting the Socket Server
+	err=iSockServ.Connect();	//KESockDefaultMessageSlots
+	if (err!=KErrNone)
+	{
+		ErrorL(_L("Socket Server Error (Connect)"),err);
+		Stop();
+		return;
+	}
+
+	err=iHostResolv.Open(iSockServ, KAfInet, KProtocolInetIcmp);	// Address Resolver 
+	
+	if (err!=KErrNone)
+	{
+		ErrorL(_L("Resolver Error (Open)"),err);
+
+		Stop();
+		return;
+	}
+
+
+
+	//Report(_L("Resolver Open"));
+	iConsole->WriteLine(_L("Resolving..."));	
+	iHostResolv.GetByName(iHostname,iEntry,iStatus);
+	//Report(_L("Resolver GetByName"));
+	iStage=0;
+	//CEikonEnv::Static()->BusyMsgL(R_RESOLVING_NAME);
+
+	
+//-------------------------------------------------
+	//DO NOT REMOVE the next commented code!!!!!!!!!!!!!!!!!!
+	/*
+	//Never will be used because the socket is opened as ICMP not IP so is not usable 
+	//unless some changes are made to the socket and packet format.
+	
+	
+	if (iHopLimit!=0)	// 0 means value not set
+	{	//Only setable for multicast adresses
+		err=iSocket.SetOpt(KSoIpTTL,KSOLSocket,iHopLimit);	//Set TTL (max. hops)
+		
+		
+		if (err==KErrNotSupported)
+			iConsole->WriteLine(_L("TTL can only be set with multicast adress (Not used)\n"));
+		else
+			if (err<0)
+			{
+				ErrorL(_L("Socket Error (SetOpt)"),err);
+				return;
+			}
+		
+	}
+--------------------------------------------------------	*/
+	IssueRequest();
+/*	iStage=0;
+	TRequestStatus *xst=&iStatus;
+	User::RequestComplete(xst,KErrNone);*/
+}
+
+void CPing::CreateSocketAOL()
+{
+	
+	iPingSender=new(ELeave) CPingSender;
+    iPingSender->ConstructL(this);	//2nd phase
+	iPingSender->FirstRunL();	//Starts packet sending
+}
+
+//Issues next RunL execution
+void CPing::IssueRequest()
+{
+	SetActive();	//Sets the object as Active.
+					//RunL will be executed when iStatus!=KRequestPending (set by CPingSender)
+}
+
+
+void CPing::RunL()
+{
+	TInt err=KErrNone;
+	TBuf<39> textIPaddress;	//text address to be displayed
+	TBuf<356> aux;
+	TInetAddr anyaddr;
+	TRequestStatus xStatus;
+
+	switch (iStage)
+	{
+	case 0:
+		//Report(_L("Resolver GetByName end"));
+		if (iStatus==KErrNotFound)
+		{//The Nameserver couldn't find the Host. 
+			TBuf<100> warn(iHostname);
+			warn.Append(_L(" not found!\n"));
+			iConsole->WriteLine(warn);
+			iHostResolv.Close();
+			Stop();
+			return;
+		}	
+		if (iStatus!=KErrNone)
+		{
+			ErrorL(_L("Resolver Error (GetByName)"),iStatus.Int());
+			iHostResolv.Close();
+			//iSockServ.Close();
+			Stop();
+			return;
+		}
+
+		iHostResolv.Close();
+		iHostAddr = TInetAddr::Cast(iEntry().iAddr);	//host address
+
+		// The type of PING (ICMPv4 or ICMPv6) depens purely on the destination address.
+		// ...for IPv4 (or IPv4 mapped), use ICMPv4
+		// ...for true IPv6, use ICMPv6
+		iType = (iHostAddr.Family() == KAfInet6 && !iHostAddr.IsV4Mapped()) ? IPv6 : IPv4;
+
+		iHostAddr.Output(textIPaddress);
+		/*aux.Append(iEntry().iName);   // maybe the main name is not the entered
+		aux.Append(_L(" is "));
+		aux.Append(textIPaddress);
+
+		aux.AppendFormat(_L("\nUsing %d data bytes"), iPacketDataSize);
+		*/
+		aux.AppendFormat(_L("Pinging %S [%S] with %d bytes of data:\n"), &iEntry().iName, &textIPaddress, iPacketDataSize);
+		if (iPacketDataSize < TIMESTAMP_SIZE)
+			aux.AppendFormat(_L("timestamps disabled (min %d bytes)\n"), TIMESTAMP_SIZE);
+
+		//aux.Append(_L("\n\n"));
+		iConsole->WriteLine(aux);
+
+		if (iType==IPv4)
+		{
+			err=iSocket.Open(iSockServ,_L("icmp"));
+		}
+		else
+		{
+			err=iSocket.Open(iSockServ,_L("icmp6"));
+		}
+
+		if (err!=KErrNone)
+		{
+			ErrorL(_L("Socket Error (Open)"),err);
+			Stop();
+			return;
+		}
+		//iStage++;
+		
+		anyaddr.SetAddress(KInetAddrAny);	//Sniffs all packets
+		anyaddr.SetPort(KProtocolInetIcmp);	//Sniffs all packets
+
+		err=iSocket.Bind(anyaddr);
+		if (err!=KErrNone)
+		{	
+			ErrorL(_L("Socket Error (Bind)"),err);
+			Stop();
+			return;
+		}
+
+		iSocket.Connect(iHostAddr,xStatus);	//must be wait here or panic esock14
+		User::WaitForRequest(xStatus);
+		if (xStatus.Int()!=KErrNone)
+		{
+			ErrorL(_L("Socket Error (Connect)"),xStatus.Int());
+			Stop();
+			return;
+		}
+	
+		// Socket Options setting
+		if (iDebug)
+			err=iSocket.SetOpt(KSODebug,KSOLSocket,1);	//Enable debugging
+		else
+			err=iSocket.SetOpt(KSODebug,KSOLSocket,0);	//disable debugging (DEFAULT)
+            
+		if (err!=KErrNone)
+		{
+			ErrorL(_L("Socket Error (SetOpt)"),err);
+			//iHostResolv.Close();
+			iSocket.Close();
+			//iSockServ.Close();
+#ifdef IAPSETTING			
+			iGenericAgent.Close();
+#endif 			
+			Stop();
+			return;
+		}
+		//CEikonEnv::Static()->BusyMsgCancel();	//Cancel the resolving name msg
+		CreateSocketAOL();	//Creates the send A.O.
+		iSocket.Read(iReceivedData,iStatus);
+		iStage++;
+		IssueRequest();	//Prepares to receive it in RunL()
+		break;
+
+	case 1:
+		//Report(_L("Socket Read end"));
+		if (iStatus==KErrNone)
+		{
+			PrintICMPData(iReceivedData);	//The previous packet
+		}
+		else
+			ErrorL(_L("Read (Recv)"),iStatus.Int());
+
+		iConsole->UpdateStatisticsL();
+		
+		iSocket.Read(iReceivedData,iStatus);	// NEXT Packet
+		IssueRequest();	// Prepares to receive it in RunL()
+		// No more stages!
+		break;
+
+	default:
+		//CEikonEnv::Static()->InfoMsg(_L("Bad Stage!!!"));
+		EndPingL();
+	}
+
+}
+
+void CPing::DoCancel()
+	{
+	if (iStage==0)
+		{
+		iHostResolv.Cancel();
+		}
+	else if (iStage==1)	
+		{
+		//RSocket::Read has been called, so need to cancel this outstanding Read
+		iSocket.CancelRead();
+		}
+	}
+
+void CPing::CloseAll()
+	{
+	iHostResolv.Close();
+	//iSocket.CancelAll();	//Cancel all outstanding requests 
+	iSocket.Close();	
+	iSockServ.Close();
+#ifdef IAPSETTING
+	iGenericAgent.Close();
+#endif
+}
+
+// Stops Ping
+
+void CPing::EndPingL()
+{	
+	//CEikonEnv::Static()->BusyMsgCancel();	// Cancel the resolving name msg in case it wasn't
+
+	Statistics();
+	iConsole->UpdateStatisticsL();
+	
+	if (iPingSender!=0)	// Not needed if control dimmed because can't launch 2 pings
+	{
+		delete iPingSender;
+		iPingSender=0;
+	}
+
+	Cancel();
+
+	CloseAll();
+	iRunning = EFalse;
+	iConsole->OnEnd();
+}
+
+// Just checks if sending packets from a previous ping
+
+TBool CPing::IsRunning()
+{
+	return iRunning;
+}
+
+// Sends packets with an active Timer
+// Created by CPing
+// Not intended to run alone
+
+CPingSender::CPingSender():CTimer(EPriorityStandard)//,iSentData(0,0)
+{
+	CActiveScheduler::Add(this);	//Adds itself to the scheduler only the first time
+}
+
+CPingSender::~CPingSender()
+	{
+	Cancel();
+	delete iSender;
+	}
+
+void CPingSender::ConstructL(CPing *aPingModel)
+{
+	//Base class 2nd phase constructor
+	CTimer::ConstructL();
+
+	iPingModel=aPingModel;	// Poiter to the model which contains data
+	//iSentDataBuffer= HBufC8::NewL(iPingModel->iPacketDataSize + ICMP_HDRLEN);
+							//Allocates the maximum space needed the size chosen + ICMP Header
+	iSender=new(ELeave) CPingSingleSender(iPingModel);
+}
+
+
+//Issues next RunL execution
+void CPingSender::IssueRequest()
+{
+	After(iPingModel->iSecWait*SECOND);	//Also sets the object as Active
+}
+
+//Issues last RunL execution
+void CPingSender::IssueLastRequest()
+{
+	After(iPingModel->iLastSecWait*SECOND);	//Also sets the object as Active
+}
+
+
+void CPingSender::FirstRunL()
+{	
+	
+	SendFirstPacketL();
+	
+	if ((iPingModel->iSentPackets==iPingModel->iTotalPackets) && (iPingModel->iPackLimit))
+		IssueLastRequest();	//Last RunL	have a special waiting time. to receive the last reply
+	else
+		IssueRequest();	//First RunL
+}
+
+
+
+// will send all the packets. One packet each Time
+void CPingSender::RunL()
+{
+	if ((iPingModel->iSentPackets>=iPingModel->iTotalPackets) && (iPingModel->iPackLimit))
+	{
+		iPingModel->EndPingL();
+		return;
+	}
+	else	//There are packets to send or number unlimited
+	{		
+		SendPacket();
+
+		if ((iPingModel->iSentPackets>=iPingModel->iTotalPackets) && (iPingModel->iPackLimit))
+			IssueLastRequest();	//Last RunL	have a special waiting time. to receive the last reply
+		else
+			IssueRequest();	//Next RunL
+	}
+
+}
+
+
+//Creates a AO that sends a packets waits for it to be send and dies
+void CPingSender::SendFirstPacketL()
+{
+	iSender->FirstRunLD();	//Starts packet sending. Destroys itself
+}
+
+
+//Creates a AO that sends a packets waits for it to be send and dies
+void CPingSender::SendPacket()
+{
+	iSender->NextPacket();
+}
+
+//Cancel Packet Sending
+void CPingSender::DoCancel()
+	{
+	CTimer::DoCancel();
+	}
+
+
+
+
+// Used by CPingSender
+// Sends packets. Cannot be done directly by CPingSender because there are conflicts with
+//					diferent TRequestStatus.
+
+CPingSingleSender::CPingSingleSender(CPing *aPingModel):CActive(EPriorityStandard)
+{
+	iPingModel=aPingModel;	// Pointer to the model which contains data
+	CActiveScheduler::Add(this);	//Adds itself to the scheduler only the first time
+}
+
+CPingSingleSender::~CPingSingleSender()
+	{
+	Cancel();
+	}
+
+
+// Issues next RunL execution
+
+void CPingSingleSender::IssueRequest()
+{
+	SetActive();	// Sets the object as Active.
+}
+
+void CPingSingleSender::FirstRunLD()
+{	
+	iPingModel->ComposeFirstICMPPacket();
+	iPingModel->iSocket.Write(iPingModel->iPacket, iStatus); // iStatus used by CTimer
+	iPingModel->iSentPackets++;
+	iUnsent=0;
+	IssueRequest();
+}
+
+void CPingSingleSender::NextPacket()
+{	
+	if (IsActive())		// Still a packet being sent
+		iUnsent++;		// Cannot sent here because iSatus would be overwritten
+	else
+	{
+		iPingModel->ComposeICMPPacket();
+		iPingModel->iSocket.Write(iPingModel->iPacket, iStatus); // No other request waiting
+		iPingModel->iSentPackets++;
+		IssueRequest();
+	}
+}
+
+// will send all the packets. One packet each Time
+// when entering this function, 
+// it means either one packet has actually been sent, or failed
+void CPingSingleSender::RunL()
+{
+//	TBuf<50> aux;
+	
+//	if (iStatus==KErrNone)
+//		iPingModel->iSentPackets++;
+	//else if (iStatus!=KRequestPending)
+	if (iStatus!=KErrNone)
+	{
+		iPingModel->iSentPackets--;	//Packet sending failed
+		iPingModel->ErrorL(_L("Write"),iStatus.Int());
+	}
+
+	//aux.Format(_L("Write end (st=%d, sent=%d)"),iStatus,iPingModel->iSentPackets);
+	//iPingModel->WriteLineIfNotQuiet(aux);
+	iPingModel->iConsole->UpdateStatisticsL();
+	//Ignores the timer request because there are packets that should already be sent
+	if (iUnsent)
+	{
+		iPingModel->ComposeICMPPacket();
+		iPingModel->iSocket.Write(iPingModel->iPacket, iStatus); // iStatus used by CTimer
+		iPingModel->iSentPackets++;
+		iUnsent--;
+		IssueRequest();
+	}
+}
+
+// Cancel Packet Sending
+
+void CPingSingleSender::DoCancel()
+	{
+	iPingModel->iSocket.CancelWrite();
+	}