networkingtestandutils/exampleinternetutilities/PINGENG/PINGENG.CPP
changeset 0 af10295192d8
child 37 052078dda061
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 1997-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 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <pingeng.h>
       
    17 #include <e32hal.h>
       
    18 #include <icmp6_hdr.h>
       
    19 #include <in_chk.h>
       
    20 #include <commdbconnpref.h>
       
    21 #include <connpref.h>
       
    22 
       
    23 const TInt KDefaultPings =  4;
       
    24 const TInt KDefaultInterval = 1000000;
       
    25 const TInt KDefaultWait = 10000000;
       
    26 const TInt KDefaultPingSize = 32;
       
    27 const TInt KDefaultBacklog = 512;
       
    28 
       
    29 const TInt KMaxTimeOnQue=KDefaultBacklog*KDefaultInterval;
       
    30 const TInt KMaxSendTime=60000000;
       
    31 
       
    32 const TUint KIcmpHeaderSize = 8;
       
    33 const TUint KMinIpHeaderSize = 20;
       
    34 
       
    35 class CPingTimer : public CTimer
       
    36 	{
       
    37 friend class CPingEng;
       
    38 protected:
       
    39 	CPingTimer(CPingEng& aParent);
       
    40 	void RunL();
       
    41 private:
       
    42 	CPingEng& iParent;
       
    43 	};
       
    44 
       
    45 class CPingSender : public CActive
       
    46 	{
       
    47 friend class CPingEng;
       
    48 protected:
       
    49 	CPingSender(CPingEng& aParent);
       
    50 	~CPingSender();
       
    51 	void RunL();
       
    52 	void DoCancel();
       
    53 private:
       
    54 	CPingEng& iParent;
       
    55 	};
       
    56 
       
    57 class CPingReceiver : public CActive
       
    58 	{
       
    59 friend class CPingEng;
       
    60 protected:
       
    61 	CPingReceiver(CPingEng& aParent);
       
    62 	~CPingReceiver();
       
    63 	void RunL();
       
    64 	void DoCancel();
       
    65 private:
       
    66 	CPingEng& iParent;
       
    67 	};
       
    68 
       
    69 
       
    70 class HPingHeader : public TInet6HeaderICMP_Echo
       
    71 	{
       
    72 public:
       
    73 	static HPingHeader* NewL(TInt aSize = KIcmpHeaderSize, TUint aIPVersion = KAfInet);
       
    74 	~HPingHeader();
       
    75 
       
    76 	TBool VerifyRecvEcho(TInt aId);
       
    77 	TBool VerifyNonEcho(TInt aId);
       
    78 	void SetVersion(TUint aIPVersion);
       
    79 	void FormatSend(TUint aId, TUint aSeqNum);
       
    80 	TInt MaxLength();
       
    81 	TInt DataLength();
       
    82 	TPtr8* Grab();
       
    83 	TPtrC8 IcmpContents();
       
    84 
       
    85 private:
       
    86 	void ConstructL(TInt aSize, TUint aIPVersion);
       
    87 	TBool SetHeader(TUint aOffset = 0);
       
    88 	
       
    89 	HBufC8* iData;
       
    90 	TPtr8* iDataPtr;
       
    91 	TUint iIPVersion;
       
    92 	TInt iSize;
       
    93 	};
       
    94 
       
    95 enum TPingEngPanic
       
    96 	{
       
    97 
       
    98 	ETimerPriorityGreaterThanSender,	// 0
       
    99 	ESenderPrirityGreaterThanReceiver	// 1
       
   100 	};
       
   101 
       
   102 LOCAL_C void Panic(TPingEngPanic aPanic)
       
   103 //
       
   104 // Panic the user
       
   105 //
       
   106 	{
       
   107 
       
   108 	User::Panic(_L("PingEng"), aPanic);
       
   109 	}
       
   110 
       
   111 EXPORT_C TPingOptions::TPingOptions()
       
   112 //
       
   113 // Default ping options
       
   114 //
       
   115 	{
       
   116 
       
   117 	iNumberOfPings=KDefaultPings;
       
   118 	iInterval = KDefaultInterval;
       
   119 	iWait = KDefaultWait;
       
   120 	iPingSize=KDefaultPingSize;
       
   121 	iResolveAddress=EFalse;
       
   122 	iPrompt=EFalse;
       
   123 	iConnIap=0;
       
   124 	iConnSnap=0;
       
   125 	iPreload=0;
       
   126 	iBacklog=KDefaultBacklog;
       
   127 	}
       
   128 
       
   129 EXPORT_C CPingEng* CPingEng::NewL(MPingNotificationHandler& aUi)
       
   130 //
       
   131 // Create a new ping engine
       
   132 //
       
   133 	{
       
   134 
       
   135 	CPingEng* p= new(ELeave) CPingEng(aUi);
       
   136 	CleanupStack::PushL(p);
       
   137 	p->ConstructL();
       
   138 	CleanupStack::Pop(p);
       
   139 	return p;
       
   140 	}
       
   141 
       
   142 CPingEng::CPingEng(MPingNotificationHandler& aUi)
       
   143 : iUi(aUi)
       
   144 //
       
   145 // Declare a name
       
   146 //
       
   147 	{	
       
   148 	
       
   149 	__DECLARE_NAME(_S("CPingEng"));
       
   150 	}
       
   151 
       
   152 EXPORT_C CPingEng::~CPingEng()
       
   153 //
       
   154 // Destroy wot ping created
       
   155 	{
       
   156 
       
   157 	iSocket.Close();
       
   158 	iResolver.Close();
       
   159 	iConnect.Close();
       
   160 	iSocketServ.Close();
       
   161 	delete iReceiver;
       
   162 	delete iSender;
       
   163 	delete iTimer;
       
   164 	delete iRecvData;
       
   165 	delete iSendData;
       
   166 
       
   167 	EmptyPingRecordQue();
       
   168 	}
       
   169 
       
   170 void CPingEng::EmptyPingRecordQue()
       
   171 	{
       
   172 
       
   173 	while (!iQue.IsEmpty())
       
   174 		{
       
   175 		DeletePingRecord(iQue.First());
       
   176 		}
       
   177 	}
       
   178 
       
   179 void CPingEng::DeletePingRecord(TPingRecord* aRecord)
       
   180 	{
       
   181 	
       
   182 	iQue.Remove(*aRecord);
       
   183 	delete aRecord;
       
   184 	iNoInQue--;	
       
   185 	}
       
   186 
       
   187 void CPingEng::ConstructL()
       
   188 //
       
   189 // Construct and heap objects
       
   190 //
       
   191 	{
       
   192 
       
   193 	iQue.SetOffset(_FOFF(TPingRecord, iLink));
       
   194 	iTimer = new (ELeave) CPingTimer(*this);
       
   195 	iTimer->ConstructL();
       
   196 	iSender = new (ELeave) CPingSender(*this);
       
   197 	iReceiver = new (ELeave) CPingReceiver(*this);
       
   198 	User::LeaveIfError(iSocketServ.Connect());
       
   199 	}
       
   200 
       
   201 EXPORT_C void CPingEng::SetPriorities(TInt aTimerPriority, TInt aSenderPriority, TInt aReceiverPriority)
       
   202 //
       
   203 //	Set various active object priorities
       
   204 //
       
   205 	{	
       
   206 
       
   207 	__ASSERT_ALWAYS(aTimerPriority < aSenderPriority, Panic(ETimerPriorityGreaterThanSender));
       
   208 	__ASSERT_ALWAYS(aSenderPriority < aReceiverPriority, Panic(ESenderPrirityGreaterThanReceiver));
       
   209 
       
   210 	iTimer->SetPriority(aTimerPriority);
       
   211 	iSender->SetPriority(aSenderPriority);
       
   212 	iReceiver->SetPriority(aReceiverPriority);
       
   213 	}
       
   214 
       
   215 EXPORT_C void CPingEng::StartL(const TPingOptions& aOptions)
       
   216 //
       
   217 // Start a ping
       
   218 //
       
   219 	{
       
   220 
       
   221 	// Reset All Variables
       
   222 	iNrTransmitted=0;
       
   223 	iNrReceived=0;
       
   224 	iNrDuplicates=0;
       
   225 	iMinTime=KMaxTInt;
       
   226 	iMaxTime=0;
       
   227 	iSumTime=0;
       
   228 	iId=User::TickCount()&KMaxTUint16;
       
   229 	iNameEntry().iName.SetLength(0);
       
   230 	iNameEntry().iFlags=0;
       
   231 	iIsLoopback = EFalse;
       
   232 
       
   233 	iOptions=aOptions;
       
   234 
       
   235 	if(iOptions.iDestname.Length()>0)
       
   236 		{	
       
   237 
       
   238 		TInetAddr& addr = (TInetAddr&)iNameEntry().iAddr;
       
   239 
       
   240 		const TBool addressInputValid = addr.Input(iOptions.iDestname) == KErrNone;
       
   241 
       
   242 		if (addressInputValid)
       
   243 		    {
       
   244             iIsLoopback = addr.IsLoopback();
       
   245 		    }
       
   246 		        
       
   247 		iConnect.Close();
       
   248 		
       
   249 		// Make a connection only if it is required.
       
   250 		//
       
   251 		if (!iIsLoopback)
       
   252             {
       
   253             // This branch will unfortunately be taken if the call to TInetAddr.Input() fails.
       
   254 
       
   255             
       
   256     		User::LeaveIfError(iConnect.Open(iSocketServ, KConnectionTypeDefault));
       
   257 
       
   258 			if(iOptions.iConnSnap)
       
   259 				{
       
   260 				TConnSnapPref connPref(iOptions.iConnSnap);
       
   261 				User::LeaveIfError(iConnect.Start(connPref));
       
   262 				}
       
   263 			else
       
   264 				{
       
   265 				TCommDbConnPref commDbPref;
       
   266 				
       
   267 				if(iOptions.iConnIap)
       
   268 					{
       
   269 					commDbPref.SetIapId(iOptions.iConnIap);
       
   270 					}
       
   271 
       
   272 				if(!iOptions.iPrompt)
       
   273 					{
       
   274 					commDbPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
       
   275 					}
       
   276 				else
       
   277 					{
       
   278 					commDbPref.SetDialogPreference(ECommDbDialogPrefPrompt);
       
   279 					}
       
   280 				User::LeaveIfError(iConnect.Start(commDbPref));
       
   281 				}			
       
   282 			}
       
   283 
       
   284 		
       
   285         TInt err;
       
   286         
       
   287 		if (addressInputValid)
       
   288 			{
       
   289 			if(iOptions.iResolveAddress)
       
   290 				{
       
   291 				if((err=iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp, iConnect))==KErrNone)
       
   292 					{
       
   293 					iState=ELookingUp;
       
   294 					iResolver.GetByAddress(addr, iNameEntry, iSender->iStatus);
       
   295 					iSender->SetActive();
       
   296 					iTimer->After(KMaxSendTime);
       
   297 					}
       
   298 				else
       
   299 					{
       
   300 					DoError(err);
       
   301 					}
       
   302 				}
       
   303 			else
       
   304 				{
       
   305 				iSender->iStatus=KErrNone;
       
   306 				iState=ELookingUp;
       
   307 				SendCompleteL();
       
   308 				}
       
   309 			}
       
   310 		else
       
   311 			{
       
   312 			if((err=iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp, iConnect))==KErrNone)
       
   313 				{
       
   314 				iState=ELookingUp;
       
   315 				iResolver.GetByName(iOptions.iDestname, iNameEntry, iSender->iStatus);
       
   316 				iSender->SetActive();
       
   317 				iTimer->After(KMaxSendTime);
       
   318 				}
       
   319 			else
       
   320 				{
       
   321 				DoError(err);
       
   322 				}
       
   323 			}
       
   324 		}
       
   325 	else
       
   326 		{
       
   327 		DoError(KErrBadName);
       
   328 		}
       
   329 	}
       
   330 
       
   331 EXPORT_C void CPingEng::CancelAndFinished()
       
   332 //
       
   333 // Cancel from the UI
       
   334 //
       
   335 	{
       
   336 	
       
   337 	if(iState!=EStopped || iTimer->IsActive())
       
   338 		{
       
   339 		Cancel();
       
   340 		iUi.Finished(iNameEntry(), iNrTransmitted, iNrReceived, iNrDuplicates, iMinTime, iMaxTime, iSumTime, KErrCancel);
       
   341 		}
       
   342 	}
       
   343 
       
   344 EXPORT_C void CPingEng::Cancel()
       
   345 //
       
   346 // Cancel a ping in progress
       
   347 //
       
   348 	{
       
   349 
       
   350 	iSender->Cancel();
       
   351 	iReceiver->Cancel();	
       
   352 	iTimer->Cancel();
       
   353 	iSocket.Close();
       
   354 	iConnect.Close();
       
   355 	iResolver.Close();
       
   356 
       
   357 	EmptyPingRecordQue();
       
   358 
       
   359 	iState=EStopped;
       
   360 	}
       
   361 
       
   362 void CPingEng::DoError(TInt aError)
       
   363 //
       
   364 // Generate an error from somewhere
       
   365 //
       
   366 	{
       
   367 	
       
   368 	Cancel();
       
   369 	iTimer->SetActive();
       
   370 	TRequestStatus* p = &iTimer->iStatus;
       
   371 	User::RequestComplete(p, aError);
       
   372 	}
       
   373 
       
   374 void CPingEng::TimerComplete()
       
   375 //
       
   376 // Timer event completed
       
   377 //
       
   378 	{
       
   379 
       
   380 	if(iTimer->iStatus==KErrNone)
       
   381 		{
       
   382 
       
   383 		if((iOptions.iNumberOfPings && iNrTransmitted>=iOptions.iNumberOfPings)
       
   384 			|| iSender->IsActive())
       
   385 			{
       
   386 		
       
   387 			Cancel();
       
   388 			iUi.Finished(iNameEntry(), iNrTransmitted, iNrReceived, iNrDuplicates, iMinTime, iMaxTime, iSumTime, KErrTimedOut);
       
   389 			}
       
   390 		else
       
   391 			{
       
   392 			PurgeQue();
       
   393 			NextSend();
       
   394 			}
       
   395 		}
       
   396 	else
       
   397 		{
       
   398 		iUi.Finished(iNameEntry(), iNrTransmitted, iNrReceived, iNrDuplicates, iMinTime, iMaxTime, iSumTime, iTimer->iStatus.Int());
       
   399 		}
       
   400 	}
       
   401 
       
   402 void CPingEng::SendCompleteL()
       
   403 //
       
   404 // A send operation has completed
       
   405 //
       
   406 	{
       
   407 	if(iState==ELookingUp)
       
   408 		{
       
   409 		iResolver.Close();
       
   410 		}
       
   411 
       
   412 	if(iSender->iStatus!=KErrNone)
       
   413 		{
       
   414  		DoError(iSender->iStatus.Int());
       
   415 		return;
       
   416 		}
       
   417 
       
   418 	iTimer->Cancel();
       
   419 
       
   420 	if(iState==ELookingUp) // Intiate the ping process
       
   421 		{
       
   422 		delete iSendData;
       
   423 		iSendData = NULL;
       
   424 		delete iRecvData;
       
   425 		iRecvData = NULL;
       
   426 		TInt res=KErrNone;
       
   427 
       
   428 		// Set up socket and recieve/send packets depending on address type.
       
   429 		switch(iNameEntry().iAddr.Family())
       
   430 			{
       
   431 		case KAfInet:
       
   432 			{
       
   433 			iSendData = HPingHeader::NewL(iOptions.iPingSize);
       
   434 			iRecvData = HPingHeader::NewL(iOptions.iPingSize);
       
   435 			if(!iRecvData || !iSendData)
       
   436 				{
       
   437 				DoError(KErrNoMemory);
       
   438 				return;
       
   439 				}
       
   440 			
       
   441 			if (iIsLoopback)
       
   442 			    {
       
   443     			res=iSocket.Open(iSocketServ, KAfInet, KSockDatagram, KProtocolInetIcmp);
       
   444 			    }
       
   445 			else
       
   446 		        {
       
   447       			res=iSocket.Open(iSocketServ, KAfInet, KSockDatagram, KProtocolInetIcmp, iConnect);
       
   448 		        }
       
   449 			break;
       
   450 			}
       
   451 		case KAfInet6:
       
   452 			{
       
   453 			iSendData = HPingHeader::NewL(iOptions.iPingSize, KAfInet6);
       
   454 			iRecvData = HPingHeader::NewL(iOptions.iPingSize, KAfInet6);
       
   455 			if(!iRecvData || !iSendData)
       
   456 				{
       
   457 				DoError(KErrNoMemory);
       
   458 				return;
       
   459 				}
       
   460 
       
   461 			if (iIsLoopback)
       
   462 			    {
       
   463     			res=iSocket.Open(iSocketServ, KAfInet, KSockDatagram, KProtocolInet6Icmp);
       
   464 			    }
       
   465 			else
       
   466 			    {
       
   467     			res=iSocket.Open(iSocketServ, KAfInet, KSockDatagram, KProtocolInet6Icmp, iConnect);
       
   468 			    }
       
   469 			break;
       
   470 			}
       
   471 		default:
       
   472 			DoError(KErrGeneral);
       
   473 			return;
       
   474 			}
       
   475 			
       
   476 		if(res==KErrNone)
       
   477 			{
       
   478 			res=iSocket.SetOpt(KSORecvBuf, KSOLSocket, iRecvData->MaxLength());
       
   479 			}
       
   480 		if(res==KErrNone)
       
   481 			{
       
   482 			res=iSocket.SetOpt(KSOSendBuf, KSOLSocket, iSendData->MaxLength());
       
   483 			}
       
   484 
       
   485 		if(res!=KErrNone)
       
   486 			{
       
   487 			DoError(res);
       
   488 			return;
       
   489 			}
       
   490 
       
   491 		// Start the receiver
       
   492 		iSocket.RecvFrom(*(iRecvData->Grab()), iSrcAddr, 0, iReceiver->iStatus);
       
   493 		iReceiver->SetActive();
       
   494 		
       
   495 		// Tell the UI
       
   496 		iUi.Pinging(iNameEntry(),iOptions.iPingSize);
       
   497 		iState=ESending;
       
   498 	    	NextSend();
       
   499 		}
       
   500 	else // Start appropriate timer
       
   501 		{
       
   502 
       
   503 		iUi.Sent();
       
   504 		if(!iOptions.iNumberOfPings || iNrTransmitted<iOptions.iNumberOfPings)
       
   505 			{
       
   506 			if(iOptions.iPreload || !iOptions.iInterval.Int())
       
   507 				{
       
   508 				if(iOptions.iPreload>0)
       
   509 					{
       
   510 					--iOptions.iPreload;
       
   511 					}
       
   512 				iTimer->iStatus=KErrNone;
       
   513 				TimerComplete();
       
   514 				}
       
   515 			else
       
   516 				{
       
   517 				iTimer->After(iOptions.iInterval);
       
   518 				}
       
   519 			}
       
   520 		else if(iNrReceived)
       
   521 			{
       
   522 			iTimer->After(iMaxTime>500000 ? (iMaxTime*5) : 1000000);
       
   523 			}
       
   524 		else
       
   525 			{
       
   526 			iTimer->After(iOptions.iWait);
       
   527 			}
       
   528 		}
       
   529 	}
       
   530 
       
   531 
       
   532 void CPingEng::NextSend()
       
   533 //
       
   534 // Initiate the next send
       
   535 //
       
   536 	{
       
   537 	TPingRecord* r = new TPingRecord(iNrTransmitted);
       
   538 	if(!r)
       
   539 		{
       
   540 		DoError(KErrNoMemory);
       
   541 		return;
       
   542 		}
       
   543 
       
   544 	iQue.AddLast(*r);
       
   545 	iNoInQue++;
       
   546 
       
   547 	if(iNoInQue > iOptions.iBacklog)
       
   548 		{
       
   549 		DeletePingRecord(iQue.First());
       
   550 		}
       
   551 
       
   552 	iSendData->FormatSend(iId, iNrTransmitted++);
       
   553 	iSocket.SendTo(*(iSendData->Grab()), iNameEntry().iAddr, iSendFlags, iSender->iStatus);
       
   554 	iSender->SetActive();
       
   555 	iTimer->After(KMaxSendTime);
       
   556 
       
   557 	}
       
   558 
       
   559 void CPingEng::SendDoCancel()
       
   560 //
       
   561 // A send operation requires cancelling
       
   562 //
       
   563 	{
       
   564 
       
   565 	if(iState==ELookingUp)
       
   566 		{
       
   567 		iResolver.Cancel();
       
   568 		}
       
   569 	else if(iState==ESending)
       
   570 		{
       
   571 		iSocket.CancelSend();
       
   572 		}
       
   573 	}
       
   574 
       
   575 void CPingEng::RecvComplete()
       
   576 //
       
   577 // A recv operation has completed
       
   578 //
       
   579 	{
       
   580 
       
   581 	if(iReceiver->iStatus==KErrNone)
       
   582 		{
       
   583 		
       
   584 		if(iRecvData->VerifyRecvEcho(iId))
       
   585 			{
       
   586 			TSglQueIter<TPingRecord> iter(iQue);
       
   587 		    	TPingRecord* p=0;
       
   588 			while((p=iter++)!=0)
       
   589 				{
       
   590 				if(iRecvData->Sequence() == p->iSeqNr)
       
   591 					{
       
   592 					++iNrReceived;
       
   593 
       
   594 					TTime now;
       
   595 					now.UniversalTime();
       
   596 					TTimeIntervalMicroSeconds32 word = I64LOW(now.MicroSecondsFrom(p->iSendTime).Int64());
       
   597 					
       
   598 					iMaxTime = word.Int()>iMaxTime ? word.Int() : iMaxTime;
       
   599 					iMinTime = word.Int()<iMinTime ? word.Int() : iMinTime;
       
   600 					iSumTime += word.Int();
       
   601 
       
   602 					iUi.Reply(iSrcAddr, iRecvData->DataLength(), p->iSeqNr, word);
       
   603 
       
   604 					DeletePingRecord(p);
       
   605 
       
   606 					if(iQue.IsEmpty() && iOptions.iNumberOfPings && iNrReceived>=iOptions.iNumberOfPings 
       
   607 						 && iNrTransmitted>=iOptions.iNumberOfPings)
       
   608 						{
       
   609 						Cancel();
       
   610 						iUi.Finished(iNameEntry(), iNrTransmitted, iNrReceived, iNrDuplicates, iMinTime, iMaxTime, iSumTime, KErrNone);
       
   611 						return;
       
   612 						}
       
   613 					break;
       
   614 					}
       
   615 				}
       
   616 			if(p==0)
       
   617 				{
       
   618 		        	++iNrDuplicates;
       
   619 				}
       
   620 			}
       
   621 		else if(iRecvData->VerifyNonEcho(iId))
       
   622 			{
       
   623 			if(iNameEntry().iAddr.Family()==KAfInet)
       
   624 				{
       
   625 				iUi.Icmp4Message(iSrcAddr, iRecvData->Type(), iRecvData->Code(), iRecvData->IcmpContents());
       
   626 				}
       
   627 			else
       
   628 				{
       
   629 				iUi.Icmp6Message(iSrcAddr, iRecvData->Type(), iRecvData->Code());
       
   630 				}
       
   631 			}
       
   632 			
       
   633 		iSocket.RecvFrom(*(iRecvData->Grab()), iSrcAddr, 0, iReceiver->iStatus);
       
   634 		iReceiver->SetActive();
       
   635 		}
       
   636 	else
       
   637 		{
       
   638 		DoError(iReceiver->iStatus.Int());
       
   639 		}
       
   640 	}
       
   641 
       
   642 void CPingEng::PurgeQue()
       
   643 //
       
   644 // Purge the que of things that linger about for too long
       
   645 //
       
   646 	{
       
   647 
       
   648 	TTime shortTimeAgo;
       
   649 	shortTimeAgo.UniversalTime();
       
   650 	shortTimeAgo -= TTimeIntervalMicroSeconds32(Max(KMaxTimeOnQue, iOptions.iWait.Int()));
       
   651 
       
   652 	TSglQueIter<TPingRecord> iter(iQue);
       
   653 	TPingRecord* p;
       
   654 	while((p=iter++)!=0)
       
   655 		{
       
   656 		if(p->iSendTime < shortTimeAgo)
       
   657 
       
   658 			{
       
   659 			DeletePingRecord(p);
       
   660 			}
       
   661 		else
       
   662 			{
       
   663 			break;
       
   664 			}
       
   665 		}
       
   666 	}
       
   667 
       
   668 void CPingEng::RecvDoCancel()
       
   669 //
       
   670 // A send operation requires cancelling
       
   671 //
       
   672 	{
       
   673 
       
   674 	iSocket.CancelRecv();
       
   675 	}
       
   676 
       
   677 CPingTimer::CPingTimer(CPingEng& aParent)
       
   678 //
       
   679 // To time events
       
   680 //
       
   681 	: CTimer(EPingTimerPriority), iParent(aParent)
       
   682 	{
       
   683 	
       
   684 	CActiveScheduler::Add(this);
       
   685 	__DECLARE_NAME(_S("CPingTimer"));
       
   686 	}
       
   687 
       
   688 void CPingTimer::RunL()
       
   689 //
       
   690 //	Timer is complete
       
   691 //
       
   692 	{
       
   693 
       
   694 	iParent.TimerComplete();
       
   695 	}
       
   696 
       
   697 CPingSender::CPingSender(CPingEng& aParent)
       
   698 //
       
   699 // C'tor
       
   700 //
       
   701 	: CActive(EPingSenderPriority), iParent(aParent)
       
   702 	{
       
   703 	
       
   704 	CActiveScheduler::Add(this);
       
   705 	__DECLARE_NAME(_S("CPingSender"));
       
   706 	}
       
   707 
       
   708 CPingSender::~CPingSender()
       
   709 //
       
   710 // D'tor cancels
       
   711 //
       
   712 	{
       
   713 
       
   714 	Cancel();
       
   715 	}
       
   716 
       
   717 void CPingSender::RunL()
       
   718 //
       
   719 // Upcall to parent
       
   720 //
       
   721 	{
       
   722 
       
   723 	iParent.SendCompleteL();
       
   724 	}
       
   725 
       
   726 void CPingSender::DoCancel()
       
   727 //
       
   728 // Get parent to cancel send
       
   729 //
       
   730 	{
       
   731 	
       
   732 	iParent.SendDoCancel();
       
   733 	}
       
   734 
       
   735 CPingReceiver::CPingReceiver(CPingEng& aParent)
       
   736 //
       
   737 // C'tor
       
   738 //
       
   739 	: CActive(EPingReceiverPriority), iParent(aParent)
       
   740 	{
       
   741 	
       
   742 	CActiveScheduler::Add(this);
       
   743 	__DECLARE_NAME(_S("CPingReceiver"));
       
   744 	}
       
   745 
       
   746 CPingReceiver::~CPingReceiver()
       
   747 //
       
   748 // D'tor cancels
       
   749 //
       
   750 	{
       
   751 
       
   752 	Cancel();
       
   753 	}
       
   754 
       
   755 void CPingReceiver::RunL()
       
   756 //
       
   757 // Upcall to parent
       
   758 //
       
   759 	{
       
   760 
       
   761 	iParent.RecvComplete();
       
   762 	}
       
   763 
       
   764 void CPingReceiver::DoCancel()
       
   765 //
       
   766 // Get parent to cancel send
       
   767 //
       
   768 	{
       
   769 	
       
   770 	iParent.RecvDoCancel();
       
   771 	}
       
   772 
       
   773 TPingRecord::TPingRecord(TUint aSeqNr)
       
   774 //
       
   775 // Create new ping record
       
   776 //
       
   777 	{
       
   778 	
       
   779 	iSeqNr = aSeqNr&KMaxTUint16;
       
   780 	iSendTime.UniversalTime();
       
   781 	}
       
   782 
       
   783 HPingHeader::~HPingHeader()
       
   784 //
       
   785 // D'tor deletes 
       
   786 //
       
   787 	{
       
   788 	
       
   789 	delete iData;
       
   790 	delete iDataPtr;
       
   791 	}
       
   792 
       
   793 HPingHeader* HPingHeader::NewL(TInt aSize, TUint aIPVersion)
       
   794 //
       
   795 // Create a new ping header
       
   796 //
       
   797 	{
       
   798 	
       
   799 	HPingHeader* h = new(ELeave) HPingHeader();
       
   800 
       
   801 	CleanupStack::PushL(h);
       
   802 	h->ConstructL(aSize, aIPVersion);
       
   803 	CleanupStack::Pop(h);	
       
   804 
       
   805 	return h;
       
   806 	}
       
   807 
       
   808 void HPingHeader::ConstructL(TInt aSize, TUint aIPVersion)
       
   809 	{
       
   810 	
       
   811 	iData = HBufC8::NewL(aSize);
       
   812 	iDataPtr = new(ELeave) TPtr8(iData->Des());
       
   813 	iSize = aSize < KIcmpHeaderSize ? KIcmpHeaderSize : aSize;
       
   814 	
       
   815 	iData->Des().FillZ();	
       
   816 	SetVersion(aIPVersion);
       
   817 	}
       
   818 
       
   819 void HPingHeader::SetVersion(TUint aIPVersion)
       
   820 //
       
   821 // To set IP version of packet
       
   822 // 
       
   823 	{
       
   824 	
       
   825 	iIPVersion = aIPVersion; 
       
   826 	}
       
   827 
       
   828 TInt HPingHeader::MaxLength()
       
   829 //
       
   830 // To get packet data maximum length
       
   831 // 
       
   832 	{
       
   833 	
       
   834 	return iData->Des().MaxLength(); 
       
   835 	}
       
   836 
       
   837 TInt HPingHeader::DataLength()
       
   838 //
       
   839 // To get packet data length
       
   840 // 
       
   841 	{
       
   842 	
       
   843 	return iData->Des().Length(); 
       
   844 	}
       
   845 
       
   846 TPtrC8 HPingHeader::IcmpContents()
       
   847 //
       
   848 // To get the icmp contents from packet data
       
   849 // 
       
   850 	{
       
   851        
       
   852 	return iData->Des().Mid(4, iData->Length()-4); 
       
   853 	}
       
   854 
       
   855 TPtr8* HPingHeader::Grab()
       
   856 //
       
   857 // To get data far a send or receive operation
       
   858 // 
       
   859 	{
       
   860 
       
   861 	iDataPtr->Copy(iData->Des());
       
   862 	return iDataPtr;
       
   863 	}
       
   864 	
       
   865 void HPingHeader::FormatSend(TUint aId, TUint aSeqNum)
       
   866 //
       
   867 // Format an ICMP packet to send
       
   868 //
       
   869 	{
       
   870 	
       
   871 	TUint type;
       
   872 	TUint code;
       
   873 	TChecksum sum;
       
   874 
       
   875 	// Configure version
       
   876 	if(iIPVersion == KAfInet)
       
   877 		{
       
   878 		type = KIPv4PingTypeEchoRequest;
       
   879 		code = KIPv4PingCodeEcho;
       
   880 		}
       
   881 	else
       
   882 		{
       
   883 		type = KIPv6PingTypeEchoRequest;
       
   884 		code = KIPv6PingCodeEcho;
       
   885 		}
       
   886 
       
   887 	// Fill header
       
   888 	SetType(static_cast<TUint8>(type));
       
   889 	SetCode(static_cast<TUint8>(code));
       
   890 	SetIdentifier(static_cast<TUint16>(aId));
       
   891 	SetSequence(static_cast<TUint16>(aSeqNum));
       
   892 
       
   893     // Zero checksum
       
   894     SetChecksum(0);
       
   895     
       
   896     // Copy the header to the data descriptor
       
   897     iData->Des().Copy(reinterpret_cast<TUint8*>(this), KIcmpHeaderSize);
       
   898     
       
   899     // Adjust the length for the appropriate ping size
       
   900     iData->Des().SetLength(iSize);
       
   901 
       
   902     // Fill ping data
       
   903     if (iSize > KIcmpHeaderSize)
       
   904         {
       
   905     	TInt i = 0;
       
   906     	TUint8 dataChar = 'a';
       
   907         TInt dataLen = iSize - KIcmpHeaderSize;
       
   908         TPtr8 dataPtr = iData->Des().MidTPtr(KIcmpHeaderSize, dataLen);
       
   909 
       
   910     	for (i = 0; i < dataLen; i++ )
       
   911     	    {
       
   912     	    dataPtr[i] = dataChar;
       
   913     	    if (dataChar == 'z')
       
   914     	        {
       
   915     	        dataChar = 'a';
       
   916     	        }
       
   917     	    else
       
   918     	        {
       
   919     	        dataChar++;
       
   920     	        }
       
   921     	    }
       
   922         }
       
   923     
       
   924 	// Compute checksum
       
   925 	sum.Add(reinterpret_cast<const TUint16*>(iData->Ptr()), iSize);
       
   926 	SetChecksum(sum.Sum());
       
   927 	}
       
   928 
       
   929 TBool HPingHeader::SetHeader(TUint aOffset)
       
   930 //
       
   931 // Set the header from an Icmp reply
       
   932 // 
       
   933 	{
       
   934 	
       
   935 	const TUint8* buffData; 
       
   936 	
       
   937 	// Check size
       
   938 	if(DataLength() < (TInt)KIcmpHeaderSize)
       
   939 		{
       
   940 		return EFalse;
       
   941 		}
       
   942 	
       
   943 	buffData = iData->Des().Ptr();
       
   944 
       
   945 	if(!buffData)
       
   946 		{
       
   947 		return EFalse;
       
   948 		}
       
   949 	
       
   950 	// Fill TInet6HeaderICMP_Echo from the buffer
       
   951 	for(int k=0;k<(TInt)KIcmpHeaderSize;k++)
       
   952 		{
       
   953 		i[k] = *(buffData + k + aOffset);
       
   954 		}
       
   955 
       
   956 	return ETrue;
       
   957 	}
       
   958 
       
   959 TBool HPingHeader::VerifyRecvEcho(TInt aId)
       
   960 //
       
   961 // Verifiy header is valid echo reply
       
   962 //
       
   963 	{
       
   964 	
       
   965 	TBool ret = ETrue;
       
   966 	TUint typeCheck;
       
   967 	TUint codeCheck;
       
   968 
       
   969 	// Fill TInet6HeaderICMP_Echo from packet data
       
   970 	ret = SetHeader();
       
   971 	
       
   972 	// Look at IP version
       
   973 	if(iIPVersion == KAfInet)
       
   974 		{
       
   975 		typeCheck = KIPv4PingTypeEchoReply;
       
   976 		codeCheck = KIPv4PingCodeEcho;
       
   977 		}
       
   978 	else
       
   979 		{
       
   980 		typeCheck = KIPv6PingTypeEchoReply;
       
   981 		codeCheck = KIPv6PingCodeEcho;
       
   982 		}
       
   983 		
       
   984 	// Wrong packet type or code
       
   985 	if(ret && (Type() != typeCheck || Code() != codeCheck))
       
   986 		{
       
   987 		ret = EFalse;
       
   988 		}
       
   989 
       
   990 	// Wrong packet identifier
       
   991 	if(ret && Identifier() != aId)
       
   992 		{
       
   993 		ret = EFalse;
       
   994 		}
       
   995 
       
   996 	return ret;
       
   997 	}
       
   998 
       
   999 TBool HPingHeader::VerifyNonEcho(TInt aId)
       
  1000 //
       
  1001 // Verify header which is not echo reply
       
  1002 // 
       
  1003 	{
       
  1004 	
       
  1005 	// Fill TInet6HeaderICMP_Echo from packet data
       
  1006 	TBool ret = SetHeader();
       
  1007 
       
  1008 	// Look at IP version
       
  1009 	if(ret && iIPVersion == KAfInet)	// IP4
       
  1010 		{
       
  1011 		switch(Type())
       
  1012 			{
       
  1013 		case KIPv4PingTypeUnreachable:
       
  1014 		case KIPv4PingTypeSourceQuench:
       
  1015 		case KIPv4PingTypeRedirect:
       
  1016 		case KIPv4PingTypeTimeExceeded:
       
  1017 		case KIPv4PingTypeBadParameter:
       
  1018 			break;
       
  1019 		default:
       
  1020 			ret = EFalse;
       
  1021 			}
       
  1022 	
       
  1023 		if(ret && (DataLength() < (TInt)KIcmpHeaderSize))
       
  1024 			{
       
  1025 		    	ret = EFalse;
       
  1026 			}
       
  1027 
       
  1028 		if(ret)
       
  1029 			{
       
  1030 			ret = SetHeader(KIcmpHeaderSize + KMinIpHeaderSize);
       
  1031 			if(ret && (Type() != KIPv4PingTypeEchoRequest || Identifier() != aId))
       
  1032 				{
       
  1033 				ret = EFalse;
       
  1034 				}
       
  1035 			}
       
  1036 		}
       
  1037 	else
       
  1038 		{				// IP6
       
  1039 		switch(Type())
       
  1040 			{
       
  1041 		case KIPv6PingTypeUnreachable:
       
  1042 		case KIPv6PingTypePacketTooBig:
       
  1043 		case KIPv6PingTypeTimeExeeded:
       
  1044 		case KIPv6PingTypeParamProblem:
       
  1045 			break;
       
  1046 		default:
       
  1047 			ret = EFalse;
       
  1048 			}
       
  1049 		}
       
  1050 
       
  1051 	return ret;
       
  1052 	}
       
  1053