commands/ping/pingmodel.cpp
changeset 0 7f656887cf89
child 103 56b6ee983610
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 // Accenture - minor mods to work as an fshell command and fixes to broken logic
       
    13 //
       
    14 // Description:
       
    15 // pingmodel.cpp - icmp echo client engine
       
    16 // This software has been implemented in the 6PACK
       
    17 // project at the Mobile Networks Laboratory (MNW)
       
    18 // http://www.research.nokia.com/projects/6pack/
       
    19 // REMARKS:
       
    20 // The application is prepared to admit the option Hop Limit and
       
    21 // Numeric output (no name resolution), but these options are not used
       
    22 // because the socket is open in ICMP mode.  To use them need an IP
       
    23 // socket and IP packets to set the options. Some code is commented and
       
    24 // can be used in case of need
       
    25 //
       
    26 
       
    27 
       
    28 
       
    29 #ifdef IAPSETTING
       
    30 #include <commdb.h>
       
    31 #endif
       
    32 
       
    33 #include <e32math.h>
       
    34 #include <e32std.h>
       
    35 //#include <eikenv.h>
       
    36 //#include <netdial.h>
       
    37 
       
    38 // IPv6 changes CPing::iType, ComposeFirstIcmpPacket()- ICMPType, Socket Open()
       
    39 
       
    40 #include "pingmodel.h"
       
    41 
       
    42 //#include <pingapp.rsg> //resource is not needed as console app
       
    43 
       
    44 #include "ping_misc.h"
       
    45 
       
    46 
       
    47 CPing::CPing():CActive(EPriorityStandard),iPacket(0,0),iReceivedData(0,0)
       
    48 {
       
    49 	CActiveScheduler::Add(this);	//Adds itself to the scheduler only the first time
       
    50 }
       
    51 
       
    52 
       
    53 
       
    54 //Sets all default values. Actually it's no more a L function
       
    55 void CPing::ConstructL(TPreferences aPref)
       
    56 {
       
    57 
       
    58 	// Base class second-phase construction.
       
    59 
       
    60 	//iHostname=_L("bart.research.nokia.com");	//default initial addr
       
    61 	//iHostname=_L("127.0.0.1");	//default initial addr
       
    62 	//iHostname=_L("dead::beef");	//default initial addr
       
    63 	iHostname=aPref.iHostname;
       
    64 	iPackLimit = aPref.iFlags & KPingPackLimit;		//Unlimited packets
       
    65 	iTotalPackets=aPref.iTotalPackets;	//Default packet number when limited number
       
    66 	
       
    67 	iSecWait=aPref.iSecWait;		//Default 1 second
       
    68 	iPacketDataSize=aPref.iPacketDataSize;	//Default Size
       
    69 	iQuiet=aPref.iFlags & KPingQuiet;	//No packet info, just statistics
       
    70 		
       
    71 	iVerbose=aPref.iFlags & KPingVerbose;	//Verbose Output. All ICMP packets, not only Echo reply. Default no
       
    72 	iPattern.Copy(aPref.iPattern);			//Pattern 0xFF (1-filled byte)
       
    73 	
       
    74 	iDebug=aPref.iFlags & KPingDebug;		//Set SO_DEBUG flag
       
    75 	iLastSecWait=aPref.iLastSecWait;	//Default time to wait for the last packet
       
    76 
       
    77 #ifdef IAPSETTING
       
    78 	iIAP = aPref.iIAP;		
       
    79 #endif
       
    80 
       
    81 	//Not used by now
       
    82 	iNumericOutput=EFalse;	//Resolve adresses by default
       
    83 	iHopLimit=0;			//Time-to-live in hops default 255 ( 1 to 255) (0 means not set)
       
    84 
       
    85 	iDupPackets=0;			//Duplicated packets
       
    86 	iRunning=EFalse;		// Tells if there's an Instance of Ping Running
       
    87 
       
    88 
       
    89 	
       
    90 /*
       
    91 	iReceivedDataBuffer= HBufC8::NewL(iPacketDataSize + ICMP_ECHO_HEADER_SIZE);	//Maximum size of a return packet
       
    92 	TPtr8 auxPtr(iReceivedDataBuffer->Des());	//must be used here because the buffer changes
       
    93 	iReceivedData.Set(auxPtr);			//we use an aux var because can't use Des() directly Why??
       
    94 */
       
    95 }
       
    96 
       
    97 //return the current preferences
       
    98 void CPing::GetPreferences(TPreferences &aPref)
       
    99 {	
       
   100 	aPref.iFlags=0;
       
   101 	if (iQuiet)
       
   102 		aPref.iFlags|=KPingQuiet;
       
   103 	if (iVerbose)
       
   104 		aPref.iFlags|=KPingVerbose;
       
   105 	if (iPackLimit)
       
   106 		aPref.iFlags|=KPingPackLimit;
       
   107 	if (iDebug)
       
   108 		aPref.iFlags|=KPingDebug;
       
   109 
       
   110 	aPref.iSecWait=iSecWait;               //Time between sent packets (Default 1 second)
       
   111 	aPref.iPacketDataSize=iPacketDataSize;//Default Data Size (not including ICMP header)
       
   112 	aPref.iTotalPackets=iTotalPackets;  //Number of ICMP Echo Request packets to send
       
   113 	aPref.iLastSecWait=iLastSecWait;   //Time to wait for the Last packet. Default 2
       
   114 	aPref.iHostname=iHostname;		//Address to Ping
       
   115 	aPref.iPattern.Copy(iPattern);
       
   116 
       
   117 #ifdef IAPSETTING	
       
   118 	aPref.iIAP = iIAP;
       
   119 #endif
       
   120 		
       
   121 }
       
   122 
       
   123 void CPing::DefaultPreferences(TPreferences &aPref)
       
   124 {	
       
   125 	aPref.iFlags=KPingVerbose|KPingPackLimit;
       
   126 
       
   127 	aPref.iSecWait=1;               //Time between sent packets (Default 1 second)
       
   128 	aPref.iPacketDataSize=56;//Default Data Size (not including ICMP header)
       
   129 	aPref.iTotalPackets=5;  //Number of ICMP Echo Request packets to send
       
   130 	aPref.iLastSecWait=2;   //Time to wait for the Last packet. Default 2
       
   131 	aPref.iPattern=_L("FF");
       
   132 	aPref.iHostname=_L("127.0.0.1");
       
   133 #ifdef IAPSETTING
       
   134 	aPref.iIAP=1;
       
   135 #endif
       
   136 }
       
   137 
       
   138 void CPing::Statistics()
       
   139 {
       
   140 	//TBuf<300> aux(_L("==========================================\n"));
       
   141 	TBuf<300> aux(_L("\n"));
       
   142 	
       
   143 	TReal rLoss=iSentPackets-iRecvPackets-iChksumErrors;	// An error is a received but wrong packet
       
   144 										//is not masked as received because of time calculations
       
   145 	if (rLoss<0) 
       
   146 		rLoss=0;
       
   147 	TReal rSent=iSentPackets;
       
   148 	TReal r;
       
   149 	if (rSent>0)
       
   150 		r=rLoss/rSent;
       
   151 	else
       
   152 		r=0;
       
   153 
       
   154 	aux.AppendFormat(_L("Lost: %.1f%% Bad: %d"), r*100, iChksumErrors);
       
   155 
       
   156 	//If there's a timestamp and data received
       
   157 	if ((iRecvPackets>0) && (iPacketDataSize >= TIMESTAMP_SIZE))
       
   158 	{
       
   159 		r=(iTimeSum/iRecvPackets);	//average in ms
       
   160 		aux.AppendFormat(_L(" Max: %d Min: %d Avg: "),iMaxTime,iMinTime);
       
   161 		TRealFormat format;	//no decimals
       
   162 		format.iType|=KDoNotUseTriads;	// no thousands separatorlast
       
   163 		aux.AppendNum(r,format);
       
   164 		aux.Append(_L(" ms"));
       
   165 	}
       
   166 
       
   167 	if (iDupPackets>0)
       
   168 		aux.AppendFormat(_L(" Dup: %d"),iDupPackets);
       
   169 
       
   170 	//aux.Append(_L("\n==========================================\n"));
       
   171 	iConsole->WriteLine(aux);
       
   172 }
       
   173 
       
   174 // Use when data is not going to be displayed in Quiet mode
       
   175 void CPing::WriteLineIfNotQuiet(const TDesC& abuf)
       
   176 {
       
   177 	if (!iQuiet)
       
   178 		iConsole->WriteLine(abuf);
       
   179 }
       
   180 
       
   181 TDes* CPing::GetHostName()
       
   182 {
       
   183 	return &iHostname;
       
   184 }
       
   185 
       
   186 void CPing::SetHostName(const TDesC& ahostname)
       
   187 {
       
   188 	iHostname=ahostname;
       
   189 }
       
   190 
       
   191 void CPing::SetConsole(CPingContainer* aConsole)
       
   192 {
       
   193 	iConsole=aConsole;
       
   194 }
       
   195 
       
   196 CPing::~CPing()
       
   197 	{
       
   198 	Cancel();
       
   199 	delete iPacketData;		// If something leaves.
       
   200 	delete iReceivedDataBuffer;
       
   201 	CloseAll();
       
   202 	}
       
   203 
       
   204 //Shows the error and set the application as not running. 
       
   205 //Requires a return after calling it!
       
   206 void CPing::ErrorL(const TDesC& string,TInt error)
       
   207 {
       
   208 	
       
   209 	TBuf<150> aux;
       
   210 	TBuf<100> errtxt;
       
   211 
       
   212 	//CEikonEnv::Static()->GetErrorText( errtxt,error);
       
   213 	aux.Format(string);	
       
   214 	aux.Append(_L(": "));
       
   215 	aux.Append(errtxt);
       
   216 	aux.AppendFormat(_L(" (%d)\n"), error);
       
   217 	WriteLineIfNotQuiet(aux);
       
   218 	//iRunning=EFalse;
       
   219 
       
   220 	iSockErrors++;
       
   221 
       
   222 	if (error==KErrAbort)	//Critical Error
       
   223 	{
       
   224 
       
   225 /*		RNetDial xnetdial;
       
   226 		TBool active;
       
   227 
       
   228 		xnetdial.Open();
       
   229 		TInt err=xnetdial.NetworkActive(active);
       
   230 	
       
   231 		if (!active)
       
   232 		{
       
   233 			xnetdial.Start();
       
   234 			err=xnetdial.NetworkActive(active);
       
   235 		}
       
   236 */
       
   237 		EndPingL();
       
   238 		User::Leave(0);	// NOT SURE IF IT'S THE BEST WAY!!!
       
   239 	}
       
   240 
       
   241 	if (iSockErrors>5)	//To avoid a chain of errors that blocks everything. Should never happen though 
       
   242 	{
       
   243 		EndPingL();
       
   244 		User::Leave(0);	// NOT SURE IF IT'S THE BEST WAY!!!
       
   245 	}
       
   246 	
       
   247 }
       
   248 
       
   249 
       
   250 // checksum of the ICMP packet (ICMP header + data)
       
   251 TUint16 CPing::in_chksum(TUint16* data, TUint len)
       
   252 {
       
   253 	
       
   254 	TUint16 *d=data;
       
   255 	TUint left=len;
       
   256 	TUint32 sum=0;
       
   257 	TUint16 aux=0;
       
   258 	
       
   259 	while (left > 1)
       
   260 	{
       
   261 		sum += *d++;
       
   262 		left -= 2;		//because adding 16 bits numbers (2 bytes)
       
   263 	}
       
   264 
       
   265 	if (left==1)	//If odd length
       
   266 	{
       
   267 		*(TUint8*) &aux = *(TUint8*) d;
       
   268 		sum += aux;
       
   269 	}
       
   270 	
       
   271 	sum = (sum >> 16) + (sum & 0x0ffff);
       
   272 	sum += (sum >> 16);
       
   273 	aux = (TUint16) ~sum;
       
   274 
       
   275 	return aux;
       
   276 	
       
   277 }
       
   278 
       
   279 // Clears a bit from the iDup table
       
   280 
       
   281 void CPing::CLR(TUint16 num)
       
   282 {
       
   283 	TInt num256 = num % 256;		//num modulus 256
       
   284 	TInt pos = num256 >> 5;		//Position of vector iDup
       
   285 	iDup[pos] &= ~((1 << num % 32 ));
       
   286 }
       
   287 
       
   288 // Sets a bit from the iDup table
       
   289 
       
   290 void CPing::SET(TUint16 num)
       
   291 {
       
   292 	TInt num256= num % 256;		//num modulus 256
       
   293 	TInt pos=num256 >> 5;		//Position of vector iDup
       
   294 	iDup[pos] |= (1 << num % 32 );
       
   295 }
       
   296 
       
   297 // Tests if the bit is set or not
       
   298 
       
   299 TBool CPing::TEST(TUint16 num)
       
   300 {
       
   301 	TUint num256= num % 256;		//num modulus 256
       
   302 	TInt pos=num256 >> 5;		//Position of vector iDup
       
   303 	return ((iDup[pos] & (1 << num % 32)) == (TUint32)(1 << num % 32));
       
   304 }
       
   305 
       
   306 //Generates a random number using iSeed
       
   307 TUint16 CPing::RandomNumber()
       
   308 {
       
   309 	if (iSeed==0)	//Initialize seed randomly with time
       
   310 	{
       
   311 		TTime time;
       
   312         time.HomeTime();
       
   313 		iSeed=time.Int64();
       
   314     }
       
   315     return ((TUint16)Math::Rand(iSeed));	//Just take the lowest 16 bits)
       
   316 }
       
   317 
       
   318 // Composes the whole ICMP packet except time stamp and checksum
       
   319 
       
   320 void CPing::ComposeFirstICMPPacket()
       
   321 {
       
   322 	ThdrICMP *hdr;
       
   323 	TUint firstPos = 0;
       
   324 	
       
   325 	hdr = (ThdrICMP *)&iPacket[0];	// Can use this one for IPv6 because is the same format
       
   326 
       
   327 	if (iType == IPv4)
       
   328 		hdr->NetSetType(KICMPTypeEchoRequest);
       
   329 	else
       
   330 		hdr->NetSetType(KInet6ICMP_EchoRequest);
       
   331 
       
   332 	hdr->NetSetCode(KICMPCode);
       
   333 
       
   334 	iId = RandomNumber();
       
   335 	((ThdrICMP_Echo *)hdr)->NetSetId(iId);	
       
   336 	((ThdrICMP_Echo *)hdr)->NetSetSeq(0);
       
   337 	CLR(0);	// Clears the bit in the received/dup buffer
       
   338 	
       
   339 	// Jump over possible timestamp
       
   340 
       
   341 	if (iPacketDataSize >= TIMESTAMP_SIZE)
       
   342 	{
       
   343 		firstPos = TIMESTAMP_SIZE;
       
   344 	}
       
   345 
       
   346 	// The rest is filled with a pattern
       
   347 	// The last part of the packet may only be a part of the pattern
       
   348 
       
   349 	TInt i;
       
   350 	TInt j;
       
   351 
       
   352 	//First transform the pattern from text to Hexadecimal
       
   353 	TLex lex;
       
   354 	//TUint8 hex_num;
       
   355 	TBuf<2> hex_digit;
       
   356 	TBuf<2 * MAX_PATTERN_LENGTH> text_pattern;
       
   357 	TUint8 hex_pattern[MAX_PATTERN_LENGTH];
       
   358 	if (iPattern.Length() % 2 == 0)
       
   359 		text_pattern.Copy(iPattern);
       
   360 	else	//odd size so the pattern is doubled and we have a even size
       
   361 	{
       
   362 		text_pattern.Copy(iPattern);
       
   363 		text_pattern.Append(iPattern);
       
   364 	}
       
   365 
       
   366 	for (i = 0; i < text_pattern.Length(); i += 2)
       
   367 	{
       
   368 		hex_digit.Copy(text_pattern.Ptr() + i, 2);	//Copy 2 text digits 1 byte
       
   369 		lex.Assign(hex_digit);
       
   370 		lex.Val(hex_pattern[i/2], EHex);		//Can't fail because only 2 digits
       
   371 		//hex_pattern.Append((TUint8 *)&hex_num, sizeof(TUint8));	//Append the hex digit (byte)
       
   372 	}
       
   373 
       
   374 
       
   375 	
       
   376 	for (j = 0, i = firstPos; (TUint)i < iPacketDataSize; i++, j++)
       
   377 	{
       
   378 		iPacket[ICMP_ECHO_HEADER_SIZE + i] = !text_pattern.Length()
       
   379 			? (TUint8)(i % 256)
       
   380 			: hex_pattern[j % (text_pattern.Length()/2)];	//hex_pattern is half the size of text pattern
       
   381 	}
       
   382 //	TBuf8<150> prova;
       
   383 //	prova.Copy(iPacket);
       
   384 	StampPacket();
       
   385 }
       
   386 
       
   387 // Only composes timestamp and sequence number and calculates checksum
       
   388 
       
   389 void CPing::ComposeICMPPacket()
       
   390 {
       
   391 	ThdrICMP *hdr = (ThdrICMP *)&iPacket[0];
       
   392 	TUint16 seq = (TUint16)(((ThdrICMP_Echo *)hdr)->NetGetSeq() + 1);
       
   393 
       
   394 	((ThdrICMP_Echo *)hdr)->NetSetSeq(seq);	// Next seq. Number
       
   395 	CLR(seq);	// Clears the bit in the received/dup buffer
       
   396 
       
   397 	StampPacket();
       
   398 }
       
   399 
       
   400 void CPing::StampPacket()
       
   401 {
       
   402 	ThdrICMP *hdr = (ThdrICMP *)&iPacket[0];
       
   403 
       
   404 	if (iPacketDataSize >= TIMESTAMP_SIZE)
       
   405 	{
       
   406 		TTime time;
       
   407 		time.UniversalTime();
       
   408 		*(TInt64*)&iPacket[8] = time.Int64();	// Converts the time to a Int64 value
       
   409 	}
       
   410 
       
   411 	hdr->NetSetChecksum(0);
       
   412 	hdr->NetSetChecksum(in_chksum((TUint16 *)&iPacket[0], iPacketDataSize + ICMP_ECHO_HEADER_SIZE));
       
   413 }
       
   414 
       
   415 //Puts the next seq number in the packet (iPacket)
       
   416 void CPing::NextSeq()
       
   417 {
       
   418 	ThdrICMP_Echo *hdr;
       
   419 
       
   420 	hdr=(ThdrICMP_Echo *)&iPacket[8];
       
   421 	hdr->SetSeq((TUint16)((hdr->NetGetSeq()) + 1));
       
   422 }
       
   423 
       
   424 //TPtrC CPing::PacketTypev6(TInet6HeaderICMP_Echo *aHdr)
       
   425 void CPing::PacketTypev6(TDes& buf,ThdrICMP *aHdr)
       
   426 {
       
   427 	//TBuf<40> buf;
       
   428 	TInet6HeaderICMP *hdr = (TInet6HeaderICMP *)aHdr;
       
   429 	//TInet6HeaderICMP_Echo *echoHdr;
       
   430 
       
   431 	TInt8 code=hdr->Code();
       
   432 	switch(hdr->Type())
       
   433 	{
       
   434 		//Errors 0-127
       
   435 		case KInet6ICMP_Unreachable: 
       
   436 			//buf.Format(_L("type= "));
       
   437 			buf.Append(_L("Dest. Unreachable: "));
       
   438 			//buf.Format(_L("type=%d "),type);
       
   439 			switch (code)
       
   440 			{
       
   441 			case KInet6ICMP_NoRoute:
       
   442 				//buf.Append(_L("code= "));
       
   443 				buf.Append(_L("No Route "));
       
   444 				break;
       
   445 			case KInet6ICMP_AdminProhibition:
       
   446 				//buf.Append(_L("code= "));
       
   447 				buf.Append(_L("Admin. Prohibition "));
       
   448 				break;
       
   449 			case KInet6ICMP_NotNeighbour:
       
   450 				//buf.Append(_L("code= "));
       
   451 				buf.Append(_L("Not a Neighbour "));
       
   452 				break;
       
   453 			case KInet6ICMP_AddrUnreach:
       
   454 				//buf.Append(_L("code= "));
       
   455 				buf.Append(_L("Addr. Unreachable "));
       
   456 				break;
       
   457 			case KInet6ICMP_PortUnreach:
       
   458 				//buf.Append(_L("code= "));
       
   459 				buf.Append(_L("Port Unreachable "));
       
   460 				break;
       
   461 			default: buf.AppendFormat(_L("code=%d "),code);
       
   462 			}
       
   463 			break;
       
   464 		case KInet6ICMP_PacketTooBig:
       
   465 			//buf.Format(_L("type= "));
       
   466 			buf.Append(_L("Pack. Too big "));
       
   467 			break;
       
   468 		case KInet6ICMP_TimeExceeded:
       
   469 			//buf.Format(_L("type= "));
       
   470 			buf.Append(_L("Time exceeded: "));
       
   471 			switch (code)
       
   472 			{
       
   473 			case KInet6ICMP_HopLimitExceeded:
       
   474 				//buf.Append(_L("code= "));
       
   475 				buf.Append(_L("Hop Limit "));
       
   476 				break;
       
   477 			case KInet6ICMP_FragReassExceeded:
       
   478 				//buf.Append(_L("code= "));
       
   479 				buf.Append(_L("Frag. Reassembly "));
       
   480 				break;
       
   481 			default: buf.AppendFormat(_L("code=%d "),code);
       
   482 			}
       
   483 			break;
       
   484 		case KInet6ICMP_ParameterProblem:
       
   485 			//buf.Format(_L("type= "));
       
   486 			buf.Append(_L("Parameter problem: "));
       
   487 			switch (code)
       
   488 			{
       
   489 			case KInet6ICMP_ErrHdrField:
       
   490 				//buf.Append(_L("code= "));
       
   491 				buf.Append(_L("Bad header filed"));
       
   492 				break;
       
   493 			case KInet6ICMP_NextHdrUnknown:
       
   494 				//buf.Append(_L("code= "));
       
   495 				buf.Append(_L("Unknown Next Header "));
       
   496 				break;
       
   497 			case KInet6ICMP_OptionUnkown:
       
   498 				//buf.Append(_L("code= "));
       
   499 				buf.Append(_L("Unknown Option"));
       
   500 				break;
       
   501 			default: buf.AppendFormat(_L("code=%d "),code);
       
   502 			}
       
   503 			break;
       
   504 
       
   505 		//Information 128-255
       
   506 		case KInet6ICMP_EchoRequest:
       
   507 			//echoHdr=(TInet6HeaderICMP_Echo *)hdr;
       
   508 			buf.Append(_L("Echo Request "));
       
   509 			//buf.AppendFormat(_L("id= %d "),echoHdr->Identifier());
       
   510 			//buf.AppendFormat(_L("Seq= %d "),echoHdr->Sequence());
       
   511 			break;
       
   512 		case KInet6ICMP_EchoReply:
       
   513 			//echoHdr=(TInet6HeaderICMP_Echo *)hdr;
       
   514 			buf.Append(_L("Echo Reply "));
       
   515 			//buf.AppendFormat(_L("id= %d "),echoHdr->Identifier());
       
   516 			//buf.AppendFormat(_L("Seq= %d "),echoHdr->Sequence());
       
   517 			break;
       
   518 	
       
   519 		case KInet6ICMP_Redirect:
       
   520  			buf.Append(_L("Redirect "));
       
   521 			break;
       
   522 
       
   523 		case KICMPTypeRouterAdvert: 
       
   524 		case KInet6ICMP_RouterAdv:
       
   525 			buf.Append(_L("Router advertisement "));
       
   526 			break;
       
   527 
       
   528 		case KICMPTypeRouterSolicit: 
       
   529 		case KInet6ICMP_RouterSol:
       
   530 			buf.Append(_L("Router solicitation "));
       
   531 			break;
       
   532 
       
   533 		case KInet6ICMP_GroupQuery:
       
   534 			buf.Append(_L("KInet6ICMP_GroupQuery "));
       
   535 			break;
       
   536 
       
   537 		case KInet6ICMP_GroupReport:
       
   538 			buf.Append(_L("KInet6ICMP_GroupReport "));
       
   539 			break;
       
   540 
       
   541 		case KInet6ICMP_GroupDone:
       
   542 			buf.Append(_L("KInet6ICMP_GroupDone "));
       
   543 			break;
       
   544 
       
   545 		case KInet6ICMP_NeighborSol:
       
   546 			buf.Append(_L("Neighbor Solicitation "));
       
   547 			break;
       
   548 
       
   549 		case KInet6ICMP_NeighborAdv:
       
   550 			buf.Append(_L("Neighbor Advertisement "));
       
   551 			break;
       
   552 
       
   553 		default: //buf.Format(_L("Unknown ICMP Type"));
       
   554 			buf.Format(_L("Unknown ICMP Type"));
       
   555 			//buf.Format(_L("type=%d "),hdr->Type());
       
   556 	}
       
   557 	//buf.Append(_L("\n"));
       
   558 
       
   559 }
       
   560 
       
   561 TPtrC CPing::PacketType(ThdrICMP *aHdr)
       
   562 {
       
   563 	switch(aHdr->NetGetType())
       
   564 	{
       
   565 		case KICMPTypeEchoReply: return _L("ICMP Echo reply");
       
   566 		case KICMPTypeUnreachable: 
       
   567 			switch (aHdr->NetGetCode())
       
   568 			{
       
   569 				case KICMPCodeUnreachNet: return _L("Network Unreachable");
       
   570 				case KICMPCodeUnreachHost: return _L("Host Unreachable");
       
   571 				case KICMPCodeUnreachProtocol: return _L("Protocol Unreachable");
       
   572 				case KICMPCodeUnreachPort: return _L("Port Unreachable");
       
   573 				case KICMPCodeUnreachNeedFrag: return _L("Message too long. Fragmentation needed");
       
   574 				case KICMPCodeUnreachSrcRouteFail: return _L("Source Route Failed");
       
   575 				case KICMPCodeUnreachNetUnknown: return _L("Destination Network Unknown");
       
   576 				case KICMPCodeUnreachHostUnknown: return _L("Destination Host Unknown");
       
   577 				case KICMPCodeUnreachSrcHostIsolated: return _L("Source host isolated");
       
   578 				case KICMPCodeUnreachNetProhibited: return _L("Destination Network Administatively prohibited");
       
   579 				case KICMPCodeUnreachHostProhibited: return _L("Destination Host Administatively prohibited");
       
   580 				case KICMPCodeUnreachNetTOS: return _L("Network Unreachable for TOS");
       
   581 				case KICMPCodeUnreachHostTOS: return _L("Host Unreachable for TOS");
       
   582 				case KICMPCodeUnreachProhibited: return _L("Communication Administatively prohibited");
       
   583 				case KICMPCodeUnreachPrecVolation: return _L("Host Precedence violation");
       
   584 				case KICMPCodeUnreachPrecCutoff: return _L("Precedence cutoff in effect");
       
   585 				default: return _L("Unknown code for Destination Unreachable");
       
   586 			}
       
   587 		case KICMPTypeSourceQuench: return _L("Source Quench");
       
   588 		case KICMPTypeRedirect: 
       
   589 			switch (aHdr->NetGetCode())
       
   590 			{
       
   591 				case KICMPCodeRedirectNet: return _L("Redirect for network");
       
   592 				case KICMPCodeRedirectHost: return _L("Redirect for Host");
       
   593 				case KICMPCodeRedirectNetTOS: return _L("Redirect for TOS and Network");
       
   594 				case KICMPCodeRedirectHostTOS: return _L("Redirect for TOS and Host");
       
   595 				default: return _L("Unknown code for ICMP Redirect");
       
   596 			}
       
   597 		case KICMPTypeEchoRequest: return _L("Echo Request");
       
   598 		case KICMPTypeRouterAdvert: return _L("Router advertisement");
       
   599 		case KICMPTypeRouterSolicit: return _L("Router solicitation");
       
   600 		case KICMPTypeTimeExceeded: 
       
   601 			switch (aHdr->NetGetCode())
       
   602 			{
       
   603 				case KICMPCodeExceedInTransit: return _L("TTL 0 during Transit");
       
   604 				case KICMPCodeExceedInReasm: return _L("TTL 0 during Reassembly");
       
   605 				default: return _L("Unknown Code for Time exceeded type");
       
   606 			}
       
   607 		case KICMPTypeBadParameter: return _L("Parameter Problem");
       
   608 		case KICMPTypeTimeRequest: return _L("Timestamp Request");
       
   609 		case KICMPTypeTimeReply: return _L("Timestamp Reply");
       
   610 		case KICMPTypeInfoRequest: return _L("Information Request");
       
   611 		case KICMPTypeInfoReply: return _L("Information Reply");
       
   612 		case KICMPTypeMaskRequest: return _L("Adress Mask Request");
       
   613 		case KICMPTypeMaskReply: return _L("Adress Mask Reply");
       
   614 		default: return _L("Unknown ICMP Type");
       
   615 	}
       
   616 }
       
   617 
       
   618 // Shows ICMP data in the Packet and calculates time related info
       
   619 
       
   620 void CPing::PrintICMPData(const TDesC8& data)
       
   621 {
       
   622 	TBuf<300> aux;
       
   623 	ThdrICMP *hdr;	// Use only this one because the packet format for ICMP_Echo_reply is 
       
   624 					// identical in both ICMPv4 and ICMPv6
       
   625 
       
   626 	hdr=(ThdrICMP*)&data[0];	// ICMP packet format
       
   627 
       
   628 	TUint type;
       
   629 	if (iType==IPv4)
       
   630 		type=KICMPTypeEchoReply;
       
   631 	else	// ICMPv6
       
   632 		type=KInet6ICMP_EchoReply;
       
   633 
       
   634 	if (hdr->NetGetType()!=type)
       
   635 	{
       
   636 		// We want to list other packets than ICMP Echo Reply
       
   637 		if (iVerbose)
       
   638 		{
       
   639 			if (iType==IPv4)
       
   640 				aux.Format(PacketType(hdr)); // Return a description of the packet Type and Code
       
   641 			else
       
   642 			{
       
   643 				TBuf<40> auxBuf;
       
   644 				PacketTypev6(auxBuf,hdr);
       
   645 				aux.Format(auxBuf);	// Return a description of the packet Type and Code
       
   646 			}
       
   647 			aux.Append(_L("\n"));
       
   648 			WriteLineIfNotQuiet(aux);
       
   649 		}	// else we ignore them
       
   650 		return;
       
   651 	}
       
   652 	
       
   653 	// Checks if it's a the packet have a correct Id
       
   654 	// Useful if two instances if Ping running (not possible in this version)
       
   655 
       
   656 	if (((ThdrICMP_Echo *)hdr)->NetGetId()!=iId)
       
   657 	{
       
   658 		aux.Append(_L("Packet with wrong id received\n"));
       
   659 		WriteLineIfNotQuiet(aux);
       
   660 		return;
       
   661 	}
       
   662 
       
   663 	// Correct packet type and code
       
   664 
       
   665 	aux.AppendFormat(_L("Seq: %u"),((ThdrICMP_Echo *)hdr)->NetGetSeq());
       
   666 
       
   667 	// Checks if chksum is correct must be 0 (because includes the checksum field)
       
   668 	// else there's something wrong
       
   669 
       
   670 	if (iType==IPv4)
       
   671 	{
       
   672 		if (in_chksum((TUint16 *)&data[0], iPacketDataSize + ICMP_ECHO_HEADER_SIZE)!=0)
       
   673 		{
       
   674 			aux.Append(_L(" Checksum Error\n"));
       
   675 			WriteLineIfNotQuiet(aux);
       
   676 			iChksumErrors++;
       
   677 			return;
       
   678 		}
       
   679 	}
       
   680 	// ICMPv6 checks checksum internally
       
   681 
       
   682 	// Timestamp calculation
       
   683 
       
   684 	if (iPacketDataSize >= TIMESTAMP_SIZE)
       
   685 	{
       
   686 		TTime now;
       
   687 		TTime time(*(TInt64*)&data[8]);
       
   688 		now.UniversalTime();
       
   689 
       
   690 		TTimeIntervalMicroSeconds interval;
       
   691 		interval = now.MicroSecondsFrom(time);
       
   692 #ifdef I64LOW
       
   693 		TUint num = I64LOW(interval.Int64()) / 1000;
       
   694 #else
       
   695 		TUint num = interval.Int64().GetTInt() / 1000;
       
   696 #endif
       
   697 
       
   698 		if (num > iMaxTime)
       
   699 			iMaxTime = num;
       
   700 
       
   701 		if (num < iMinTime)
       
   702 			iMinTime = num;
       
   703 
       
   704 		iTimeSum += num;
       
   705 
       
   706 		aux.AppendFormat(_L("\tTime: %d ms"),num);
       
   707 	}
       
   708 	
       
   709 	iRecvPackets++;
       
   710 
       
   711 	// Test if duplicated
       
   712 
       
   713 	if (TEST(((ThdrICMP_Echo *)hdr)->NetGetSeq()))
       
   714 	{
       
   715 		aux.Append(_L("\tDUPLICATED"));
       
   716 		iRecvPackets--;	// because duplicated
       
   717 		iDupPackets++;  // to show it in statistics
       
   718 	}
       
   719 	else
       
   720 	{
       
   721 		SET(((ThdrICMP_Echo *)hdr)->NetGetSeq());	// Marks the packet as received
       
   722 	}
       
   723 
       
   724 	//aux.Append(_L("\n"));
       
   725 	WriteLineIfNotQuiet(aux);
       
   726 }
       
   727 
       
   728 void CPing::Stop()
       
   729 {
       
   730 	iRunning=EFalse;
       
   731 	iConsole->OnEnd();
       
   732 
       
   733 	//CEikonEnv::Static()->BusyMsgCancel();
       
   734 	/*
       
   735 	delete iPacketData;
       
   736 	iPacketData=NULL;
       
   737 	delete iReceivedDataBuffer;
       
   738 	iReceivedDataBuffer=NULL;
       
   739 	*/
       
   740 }
       
   741 
       
   742 void CPing::BeginL()
       
   743 {
       
   744 	TInt err=0;
       
   745 
       
   746 	if (IsRunning())	// There's another instance running
       
   747 		return;
       
   748 	else
       
   749 		iRunning=ETrue;
       
   750 
       
   751 	//INITIALIZATION
       
   752 	iSentPackets=0;		//ICMP Echo Request Packets sent
       
   753 	iRecvPackets=0;		//ICMP Echo Reply Packets received
       
   754 	iChksumErrors=0;	//Packets with errors when checking checksum
       
   755 	iSockErrors=0;		//Errors when writing/reading to/from the sockets
       
   756 	iDupPackets=0;		//Duplicated packets
       
   757 
       
   758 	iMaxTime=0;			//Time-related vars
       
   759 	iMinTime=KMaxTUint32;
       
   760 	iTimeSum=0;
       
   761 
       
   762 	if (iPacketDataSize > MAX_ICMP_PACKETSIZE)  //Is prevented in .rss file
       
   763 		iPacketDataSize = MAX_ICMP_PACKETSIZE;
       
   764 
       
   765 	
       
   766 	delete iPacketData;
       
   767 	iPacketData= HBufC8::NewL(iPacketDataSize + ICMP_HDRLEN); 
       
   768 						//Allocates space for the ICMP packet
       
   769 	TPtr8 aux(iPacketData->Des());	//weird but necessary. Cannot use Des() directly in iPacket
       
   770 	iPacket.Set(aux);
       
   771 	//iPacket.SetMax();	//because it'll be written directly using [] in Compose...() and it would crash.
       
   772 	//HUOM!!! Cannot be SetMax because sometimes the reserved size is slightly bigger. Because of block size?
       
   773 	iPacket.SetLength(iPacketDataSize + ICMP_HDRLEN);	//because it'll be written directly using [] in Compose...() and it would crash.
       
   774 
       
   775 
       
   776 	delete iReceivedDataBuffer;
       
   777 	iReceivedDataBuffer= HBufC8::NewL(iPacketDataSize + ICMP_ECHO_HEADER_SIZE);	//Maximum size of a return packet
       
   778 	TPtr8 auxPtr(iReceivedDataBuffer->Des());	//must be used here because the buffer changes
       
   779 	iReceivedData.Set(auxPtr);			//we use an aux var because can't use Des() directly Why??
       
   780 	
       
   781 	iConsole->WriteHostL(iHostname);
       
   782 	iConsole->WriteLine(_L("Connecting...\n"));	
       
   783 	iConsole->UpdateStatisticsL();
       
   784 	
       
   785 	
       
   786 #ifdef IAPSETTING
       
   787 	//CStoreableOverrideSettings *settings = NULL;
       
   788 	//CCommDbOverrideSettings::TParamList ParamList = CCommDbOverrideSettings::TParamList::EParamListPartial;
       
   789 	//CCommDbOverrideSettings::TParamList ParamList = CCommDbOverrideSettings::TParamList::EParamListPartial;
       
   790 	TCommDbDatabaseType Type = EDatabaseTypeIAP;
       
   791 	CStoreableOverrideSettings *settings = CStoreableOverrideSettings::NewL(CCommDbOverrideSettings::EParamListPartial,Type);
       
   792 	
       
   793 	CleanupStack::PushL(settings);
       
   794 	
       
   795 	CCommsDbConnectionPrefTableView::TCommDbIapConnectionPref conPref;
       
   796 	conPref.iRanking = 1;
       
   797 	conPref.iDirection = ECommDbConnectionDirectionOutgoing;
       
   798 	CCommsDbConnectionPrefTableView::TCommDbIapBearer bearer;
       
   799 	bearer.iIapId = iIAP;
       
   800 	conPref.iBearer = bearer;
       
   801 
       
   802 	err = settings->SetConnectionPreferenceOverride(conPref);
       
   803 	User::LeaveIfError(err);
       
   804 	User::LeaveIfError(iGenericAgent.Open());
       
   805     iGenericAgent.StartOutgoing(*settings,iStatus);
       
   806 	
       
   807 	err = iGenericAgent.DisableTimers();
       
   808     if (err != KErrAlreadyExists)
       
   809         User::LeaveIfError(err);
       
   810 	CleanupStack::PopAndDestroy();	
       
   811 	User::WaitForAnyRequest();
       
   812 #endif
       
   813 
       
   814 
       
   815 	//connecting the Socket Server
       
   816 	err=iSockServ.Connect();	//KESockDefaultMessageSlots
       
   817 	if (err!=KErrNone)
       
   818 	{
       
   819 		ErrorL(_L("Socket Server Error (Connect)"),err);
       
   820 		Stop();
       
   821 		return;
       
   822 	}
       
   823 
       
   824 	err=iHostResolv.Open(iSockServ, KAfInet, KProtocolInetIcmp);	// Address Resolver 
       
   825 	
       
   826 	if (err!=KErrNone)
       
   827 	{
       
   828 		ErrorL(_L("Resolver Error (Open)"),err);
       
   829 
       
   830 		Stop();
       
   831 		return;
       
   832 	}
       
   833 
       
   834 
       
   835 
       
   836 	//Report(_L("Resolver Open"));
       
   837 	iConsole->WriteLine(_L("Resolving..."));	
       
   838 	iHostResolv.GetByName(iHostname,iEntry,iStatus);
       
   839 	//Report(_L("Resolver GetByName"));
       
   840 	iStage=0;
       
   841 	//CEikonEnv::Static()->BusyMsgL(R_RESOLVING_NAME);
       
   842 
       
   843 	
       
   844 //-------------------------------------------------
       
   845 	//DO NOT REMOVE the next commented code!!!!!!!!!!!!!!!!!!
       
   846 	/*
       
   847 	//Never will be used because the socket is opened as ICMP not IP so is not usable 
       
   848 	//unless some changes are made to the socket and packet format.
       
   849 	
       
   850 	
       
   851 	if (iHopLimit!=0)	// 0 means value not set
       
   852 	{	//Only setable for multicast adresses
       
   853 		err=iSocket.SetOpt(KSoIpTTL,KSOLSocket,iHopLimit);	//Set TTL (max. hops)
       
   854 		
       
   855 		
       
   856 		if (err==KErrNotSupported)
       
   857 			iConsole->WriteLine(_L("TTL can only be set with multicast adress (Not used)\n"));
       
   858 		else
       
   859 			if (err<0)
       
   860 			{
       
   861 				ErrorL(_L("Socket Error (SetOpt)"),err);
       
   862 				return;
       
   863 			}
       
   864 		
       
   865 	}
       
   866 --------------------------------------------------------	*/
       
   867 	IssueRequest();
       
   868 /*	iStage=0;
       
   869 	TRequestStatus *xst=&iStatus;
       
   870 	User::RequestComplete(xst,KErrNone);*/
       
   871 }
       
   872 
       
   873 void CPing::CreateSocketAOL()
       
   874 {
       
   875 	
       
   876 	iPingSender=new(ELeave) CPingSender;
       
   877     iPingSender->ConstructL(this);	//2nd phase
       
   878 	iPingSender->FirstRunL();	//Starts packet sending
       
   879 }
       
   880 
       
   881 //Issues next RunL execution
       
   882 void CPing::IssueRequest()
       
   883 {
       
   884 	SetActive();	//Sets the object as Active.
       
   885 					//RunL will be executed when iStatus!=KRequestPending (set by CPingSender)
       
   886 }
       
   887 
       
   888 
       
   889 void CPing::RunL()
       
   890 {
       
   891 	TInt err=KErrNone;
       
   892 	TBuf<39> textIPaddress;	//text address to be displayed
       
   893 	TBuf<356> aux;
       
   894 	TInetAddr anyaddr;
       
   895 	TRequestStatus xStatus;
       
   896 
       
   897 	switch (iStage)
       
   898 	{
       
   899 	case 0:
       
   900 		//Report(_L("Resolver GetByName end"));
       
   901 		if (iStatus==KErrNotFound)
       
   902 		{//The Nameserver couldn't find the Host. 
       
   903 			TBuf<100> warn(iHostname);
       
   904 			warn.Append(_L(" not found!\n"));
       
   905 			iConsole->WriteLine(warn);
       
   906 			iHostResolv.Close();
       
   907 			Stop();
       
   908 			return;
       
   909 		}	
       
   910 		if (iStatus!=KErrNone)
       
   911 		{
       
   912 			ErrorL(_L("Resolver Error (GetByName)"),iStatus.Int());
       
   913 			iHostResolv.Close();
       
   914 			//iSockServ.Close();
       
   915 			Stop();
       
   916 			return;
       
   917 		}
       
   918 
       
   919 		iHostResolv.Close();
       
   920 		iHostAddr = TInetAddr::Cast(iEntry().iAddr);	//host address
       
   921 
       
   922 		// The type of PING (ICMPv4 or ICMPv6) depens purely on the destination address.
       
   923 		// ...for IPv4 (or IPv4 mapped), use ICMPv4
       
   924 		// ...for true IPv6, use ICMPv6
       
   925 		iType = (iHostAddr.Family() == KAfInet6 && !iHostAddr.IsV4Mapped()) ? IPv6 : IPv4;
       
   926 
       
   927 		iHostAddr.Output(textIPaddress);
       
   928 		/*aux.Append(iEntry().iName);   // maybe the main name is not the entered
       
   929 		aux.Append(_L(" is "));
       
   930 		aux.Append(textIPaddress);
       
   931 
       
   932 		aux.AppendFormat(_L("\nUsing %d data bytes"), iPacketDataSize);
       
   933 		*/
       
   934 		aux.AppendFormat(_L("Pinging %S [%S] with %d bytes of data:\n"), &iEntry().iName, &textIPaddress, iPacketDataSize);
       
   935 		if (iPacketDataSize < TIMESTAMP_SIZE)
       
   936 			aux.AppendFormat(_L("timestamps disabled (min %d bytes)\n"), TIMESTAMP_SIZE);
       
   937 
       
   938 		//aux.Append(_L("\n\n"));
       
   939 		iConsole->WriteLine(aux);
       
   940 
       
   941 		if (iType==IPv4)
       
   942 		{
       
   943 			err=iSocket.Open(iSockServ,_L("icmp"));
       
   944 		}
       
   945 		else
       
   946 		{
       
   947 			err=iSocket.Open(iSockServ,_L("icmp6"));
       
   948 		}
       
   949 
       
   950 		if (err!=KErrNone)
       
   951 		{
       
   952 			ErrorL(_L("Socket Error (Open)"),err);
       
   953 			Stop();
       
   954 			return;
       
   955 		}
       
   956 		//iStage++;
       
   957 		
       
   958 		anyaddr.SetAddress(KInetAddrAny);	//Sniffs all packets
       
   959 		anyaddr.SetPort(KProtocolInetIcmp);	//Sniffs all packets
       
   960 
       
   961 		err=iSocket.Bind(anyaddr);
       
   962 		if (err!=KErrNone)
       
   963 		{	
       
   964 			ErrorL(_L("Socket Error (Bind)"),err);
       
   965 			Stop();
       
   966 			return;
       
   967 		}
       
   968 
       
   969 		iSocket.Connect(iHostAddr,xStatus);	//must be wait here or panic esock14
       
   970 		User::WaitForRequest(xStatus);
       
   971 		if (xStatus.Int()!=KErrNone)
       
   972 		{
       
   973 			ErrorL(_L("Socket Error (Connect)"),xStatus.Int());
       
   974 			Stop();
       
   975 			return;
       
   976 		}
       
   977 	
       
   978 		// Socket Options setting
       
   979 		if (iDebug)
       
   980 			err=iSocket.SetOpt(KSODebug,KSOLSocket,1);	//Enable debugging
       
   981 		else
       
   982 			err=iSocket.SetOpt(KSODebug,KSOLSocket,0);	//disable debugging (DEFAULT)
       
   983             
       
   984 		if (err!=KErrNone)
       
   985 		{
       
   986 			ErrorL(_L("Socket Error (SetOpt)"),err);
       
   987 			//iHostResolv.Close();
       
   988 			iSocket.Close();
       
   989 			//iSockServ.Close();
       
   990 #ifdef IAPSETTING			
       
   991 			iGenericAgent.Close();
       
   992 #endif 			
       
   993 			Stop();
       
   994 			return;
       
   995 		}
       
   996 		//CEikonEnv::Static()->BusyMsgCancel();	//Cancel the resolving name msg
       
   997 		CreateSocketAOL();	//Creates the send A.O.
       
   998 		iSocket.Read(iReceivedData,iStatus);
       
   999 		iStage++;
       
  1000 		IssueRequest();	//Prepares to receive it in RunL()
       
  1001 		break;
       
  1002 
       
  1003 	case 1:
       
  1004 		//Report(_L("Socket Read end"));
       
  1005 		if (iStatus==KErrNone)
       
  1006 		{
       
  1007 			PrintICMPData(iReceivedData);	//The previous packet
       
  1008 		}
       
  1009 		else
       
  1010 			ErrorL(_L("Read (Recv)"),iStatus.Int());
       
  1011 
       
  1012 		iConsole->UpdateStatisticsL();
       
  1013 		
       
  1014 		iSocket.Read(iReceivedData,iStatus);	// NEXT Packet
       
  1015 		IssueRequest();	// Prepares to receive it in RunL()
       
  1016 		// No more stages!
       
  1017 		break;
       
  1018 
       
  1019 	default:
       
  1020 		//CEikonEnv::Static()->InfoMsg(_L("Bad Stage!!!"));
       
  1021 		EndPingL();
       
  1022 	}
       
  1023 
       
  1024 }
       
  1025 
       
  1026 void CPing::DoCancel()
       
  1027 	{
       
  1028 	if (iStage==0)
       
  1029 		{
       
  1030 		iHostResolv.Cancel();
       
  1031 		}
       
  1032 	else if (iStage==1)	
       
  1033 		{
       
  1034 		//RSocket::Read has been called, so need to cancel this outstanding Read
       
  1035 		iSocket.CancelRead();
       
  1036 		}
       
  1037 	}
       
  1038 
       
  1039 void CPing::CloseAll()
       
  1040 	{
       
  1041 	iHostResolv.Close();
       
  1042 	//iSocket.CancelAll();	//Cancel all outstanding requests 
       
  1043 	iSocket.Close();	
       
  1044 	iSockServ.Close();
       
  1045 #ifdef IAPSETTING
       
  1046 	iGenericAgent.Close();
       
  1047 #endif
       
  1048 }
       
  1049 
       
  1050 // Stops Ping
       
  1051 
       
  1052 void CPing::EndPingL()
       
  1053 {	
       
  1054 	//CEikonEnv::Static()->BusyMsgCancel();	// Cancel the resolving name msg in case it wasn't
       
  1055 
       
  1056 	Statistics();
       
  1057 	iConsole->UpdateStatisticsL();
       
  1058 	
       
  1059 	if (iPingSender!=0)	// Not needed if control dimmed because can't launch 2 pings
       
  1060 	{
       
  1061 		delete iPingSender;
       
  1062 		iPingSender=0;
       
  1063 	}
       
  1064 
       
  1065 	Cancel();
       
  1066 
       
  1067 	CloseAll();
       
  1068 	iRunning = EFalse;
       
  1069 	iConsole->OnEnd();
       
  1070 }
       
  1071 
       
  1072 // Just checks if sending packets from a previous ping
       
  1073 
       
  1074 TBool CPing::IsRunning()
       
  1075 {
       
  1076 	return iRunning;
       
  1077 }
       
  1078 
       
  1079 // Sends packets with an active Timer
       
  1080 // Created by CPing
       
  1081 // Not intended to run alone
       
  1082 
       
  1083 CPingSender::CPingSender():CTimer(EPriorityStandard)//,iSentData(0,0)
       
  1084 {
       
  1085 	CActiveScheduler::Add(this);	//Adds itself to the scheduler only the first time
       
  1086 }
       
  1087 
       
  1088 CPingSender::~CPingSender()
       
  1089 	{
       
  1090 	Cancel();
       
  1091 	delete iSender;
       
  1092 	}
       
  1093 
       
  1094 void CPingSender::ConstructL(CPing *aPingModel)
       
  1095 {
       
  1096 	//Base class 2nd phase constructor
       
  1097 	CTimer::ConstructL();
       
  1098 
       
  1099 	iPingModel=aPingModel;	// Poiter to the model which contains data
       
  1100 	//iSentDataBuffer= HBufC8::NewL(iPingModel->iPacketDataSize + ICMP_HDRLEN);
       
  1101 							//Allocates the maximum space needed the size chosen + ICMP Header
       
  1102 	iSender=new(ELeave) CPingSingleSender(iPingModel);
       
  1103 }
       
  1104 
       
  1105 
       
  1106 //Issues next RunL execution
       
  1107 void CPingSender::IssueRequest()
       
  1108 {
       
  1109 	After(iPingModel->iSecWait*SECOND);	//Also sets the object as Active
       
  1110 }
       
  1111 
       
  1112 //Issues last RunL execution
       
  1113 void CPingSender::IssueLastRequest()
       
  1114 {
       
  1115 	After(iPingModel->iLastSecWait*SECOND);	//Also sets the object as Active
       
  1116 }
       
  1117 
       
  1118 
       
  1119 void CPingSender::FirstRunL()
       
  1120 {	
       
  1121 	
       
  1122 	SendFirstPacketL();
       
  1123 	
       
  1124 	if ((iPingModel->iSentPackets==iPingModel->iTotalPackets) && (iPingModel->iPackLimit))
       
  1125 		IssueLastRequest();	//Last RunL	have a special waiting time. to receive the last reply
       
  1126 	else
       
  1127 		IssueRequest();	//First RunL
       
  1128 }
       
  1129 
       
  1130 
       
  1131 
       
  1132 // will send all the packets. One packet each Time
       
  1133 void CPingSender::RunL()
       
  1134 {
       
  1135 	if ((iPingModel->iSentPackets>=iPingModel->iTotalPackets) && (iPingModel->iPackLimit))
       
  1136 	{
       
  1137 		iPingModel->EndPingL();
       
  1138 		return;
       
  1139 	}
       
  1140 	else	//There are packets to send or number unlimited
       
  1141 	{		
       
  1142 		SendPacket();
       
  1143 
       
  1144 		if ((iPingModel->iSentPackets>=iPingModel->iTotalPackets) && (iPingModel->iPackLimit))
       
  1145 			IssueLastRequest();	//Last RunL	have a special waiting time. to receive the last reply
       
  1146 		else
       
  1147 			IssueRequest();	//Next RunL
       
  1148 	}
       
  1149 
       
  1150 }
       
  1151 
       
  1152 
       
  1153 //Creates a AO that sends a packets waits for it to be send and dies
       
  1154 void CPingSender::SendFirstPacketL()
       
  1155 {
       
  1156 	iSender->FirstRunLD();	//Starts packet sending. Destroys itself
       
  1157 }
       
  1158 
       
  1159 
       
  1160 //Creates a AO that sends a packets waits for it to be send and dies
       
  1161 void CPingSender::SendPacket()
       
  1162 {
       
  1163 	iSender->NextPacket();
       
  1164 }
       
  1165 
       
  1166 //Cancel Packet Sending
       
  1167 void CPingSender::DoCancel()
       
  1168 	{
       
  1169 	CTimer::DoCancel();
       
  1170 	}
       
  1171 
       
  1172 
       
  1173 
       
  1174 
       
  1175 // Used by CPingSender
       
  1176 // Sends packets. Cannot be done directly by CPingSender because there are conflicts with
       
  1177 //					diferent TRequestStatus.
       
  1178 
       
  1179 CPingSingleSender::CPingSingleSender(CPing *aPingModel):CActive(EPriorityStandard)
       
  1180 {
       
  1181 	iPingModel=aPingModel;	// Pointer to the model which contains data
       
  1182 	CActiveScheduler::Add(this);	//Adds itself to the scheduler only the first time
       
  1183 }
       
  1184 
       
  1185 CPingSingleSender::~CPingSingleSender()
       
  1186 	{
       
  1187 	Cancel();
       
  1188 	}
       
  1189 
       
  1190 
       
  1191 // Issues next RunL execution
       
  1192 
       
  1193 void CPingSingleSender::IssueRequest()
       
  1194 {
       
  1195 	SetActive();	// Sets the object as Active.
       
  1196 }
       
  1197 
       
  1198 void CPingSingleSender::FirstRunLD()
       
  1199 {	
       
  1200 	iPingModel->ComposeFirstICMPPacket();
       
  1201 	iPingModel->iSocket.Write(iPingModel->iPacket, iStatus); // iStatus used by CTimer
       
  1202 	iPingModel->iSentPackets++;
       
  1203 	iUnsent=0;
       
  1204 	IssueRequest();
       
  1205 }
       
  1206 
       
  1207 void CPingSingleSender::NextPacket()
       
  1208 {	
       
  1209 	if (IsActive())		// Still a packet being sent
       
  1210 		iUnsent++;		// Cannot sent here because iSatus would be overwritten
       
  1211 	else
       
  1212 	{
       
  1213 		iPingModel->ComposeICMPPacket();
       
  1214 		iPingModel->iSocket.Write(iPingModel->iPacket, iStatus); // No other request waiting
       
  1215 		iPingModel->iSentPackets++;
       
  1216 		IssueRequest();
       
  1217 	}
       
  1218 }
       
  1219 
       
  1220 // will send all the packets. One packet each Time
       
  1221 // when entering this function, 
       
  1222 // it means either one packet has actually been sent, or failed
       
  1223 void CPingSingleSender::RunL()
       
  1224 {
       
  1225 //	TBuf<50> aux;
       
  1226 	
       
  1227 //	if (iStatus==KErrNone)
       
  1228 //		iPingModel->iSentPackets++;
       
  1229 	//else if (iStatus!=KRequestPending)
       
  1230 	if (iStatus!=KErrNone)
       
  1231 	{
       
  1232 		iPingModel->iSentPackets--;	//Packet sending failed
       
  1233 		iPingModel->ErrorL(_L("Write"),iStatus.Int());
       
  1234 	}
       
  1235 
       
  1236 	//aux.Format(_L("Write end (st=%d, sent=%d)"),iStatus,iPingModel->iSentPackets);
       
  1237 	//iPingModel->WriteLineIfNotQuiet(aux);
       
  1238 	iPingModel->iConsole->UpdateStatisticsL();
       
  1239 	//Ignores the timer request because there are packets that should already be sent
       
  1240 	if (iUnsent)
       
  1241 	{
       
  1242 		iPingModel->ComposeICMPPacket();
       
  1243 		iPingModel->iSocket.Write(iPingModel->iPacket, iStatus); // iStatus used by CTimer
       
  1244 		iPingModel->iSentPackets++;
       
  1245 		iUnsent--;
       
  1246 		IssueRequest();
       
  1247 	}
       
  1248 }
       
  1249 
       
  1250 // Cancel Packet Sending
       
  1251 
       
  1252 void CPingSingleSender::DoCancel()
       
  1253 	{
       
  1254 	iPingModel->iSocket.CancelWrite();
       
  1255 	}