networkingtestandutils/exampleinternetutilities/TFTPENG/TFTPENG.CPP
changeset 0 af10295192d8
child 37 052078dda061
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2001-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 // TftpEngine.CPP
       
    15 // Started by AY, May 1997
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <tftpeng.h>
       
    20 
       
    21 EXPORT_C CTftpEngine::~CTftpEngine()
       
    22     {
       
    23     Cancel();
       
    24     iSocket.Close();
       
    25     iSockServ.Close();
       
    26     iFs.Close();
       
    27     delete iTimer;
       
    28     }
       
    29 
       
    30 CTftpEngine::CTftpEngine(const TInt aPriority, MTftpNotifier& aNotifier)
       
    31     : CActive(aPriority), iNotifier(aNotifier)
       
    32     {
       
    33     CActiveScheduler::Add(this);
       
    34     }
       
    35 
       
    36 void CTftpEngine::ConstructL()
       
    37     {
       
    38 	iTimer = CTftpTimer::NewL(10, *this); 
       
    39 	iTimeOut = 30000000;
       
    40 	iAddress.SetPort(5001);		//Arbitrary port
       
    41 	User::LeaveIfError(iSockServ.Connect());
       
    42 	User::LeaveIfError(iSocket.Open(iSockServ, KAfInet, KSockDatagram, KProtocolInetUdp));
       
    43 	iSocket.Bind(iAddress);
       
    44 	User::LeaveIfError(iFs.Connect());
       
    45     }
       
    46 
       
    47 EXPORT_C void CTftpEngine::Get(const TDesC& aNetAddr, const TDesC& aName, const TDesC& aMode)
       
    48     {
       
    49         //send Get rqst. to given address, port 69 (TFTP standard)
       
    50 	iAddress.SetPort(69);
       
    51 	iAddress.Input(aNetAddr);
       
    52 	if (iFile.Replace(iFs, aName, EFileWrite|EFileShareAny) != KErrNone)
       
    53 		iNotifier.OpComplete(EFileOpenFailure, 0);
       
    54 	else
       
    55         {
       
    56         iPacket.MakeRqst(ERRQ, aName, aMode);
       
    57         iSocket.SendTo(iPacket, iAddress, 0, iStatus);
       
    58         iState = ESending;
       
    59             //start timer for rqst.
       
    60         iTimer->After(iTimeOut);
       
    61         SetActive();
       
    62         }
       
    63     }
       
    64 
       
    65 EXPORT_C void CTftpEngine::Put(const TDesC& aNetAddr, const TDesC& aName, const TDesC& aMode)
       
    66     {
       
    67     //send Put rqst. to given address, port 69 (TFTP standard)
       
    68 	iAddress.SetPort(69);
       
    69 	iAddress.Input(aNetAddr);
       
    70 	if (iFile.Open(iFs, aName, EFileRead|EFileShareAny) != KErrNone)
       
    71 		iNotifier.OpComplete(EFileOpenFailure, 0);
       
    72 	else
       
    73 		{
       
    74 		iPacket.MakeRqst(EWRQ, aName, aMode);
       
    75 		iSocket.SendTo(iPacket, iAddress, 0, iStatus);
       
    76 		iState = ESending;
       
    77         //start timer for rqst.
       
    78 		iTimer->After(iTimeOut);
       
    79 		SetActive();
       
    80 		}
       
    81     }
       
    82 
       
    83 EXPORT_C void CTftpEngine::TimerExpired()
       
    84 	{
       
    85 	Cancel();
       
    86 	iNotifier.OpComplete(ETimedOut, 0);
       
    87 	}
       
    88 
       
    89 EXPORT_C void CTftpEngine::SetTimeOut(const TInt aTimeOut)
       
    90 	{
       
    91 	iTimeOut = aTimeOut;	
       
    92 	}	
       
    93 
       
    94 void CTftpEngine::RunL()
       
    95     {
       
    96 	//cancel Timer immediately to avoid unwanted timeouts
       
    97 	iTimer->Cancel();
       
    98 
       
    99 	if (iStatus!=KErrNone)
       
   100         //the send/recv completed with an error: Terminate
       
   101 		{
       
   102 		//NOTE:must check for other states too (e.g. ESendingLastData)
       
   103 		if(iState==ESending) 
       
   104 			iNotifier.OpComplete(ESendFail, 0);
       
   105 		else if(iState==EReceiving) 
       
   106 			iNotifier.OpComplete(ERecvFail, 0);
       
   107 		else 
       
   108 			iNotifier.OpComplete(EError, 0); //temp. cover for other states
       
   109 		iState = EComplete;
       
   110 		}
       
   111 
       
   112 	else 
       
   113 		{
       
   114 		if(iState==ESendingLastAckn) 
       
   115             //transfer completed successfully: Notify
       
   116 			{
       
   117 			iState = EComplete;
       
   118 			iNotifier.OpComplete(EOpComplete, 0);
       
   119 			}
       
   120 
       
   121 		else if(iState==ESending||iState==ESendingLastData)
       
   122             //send successful, collect reply
       
   123 			{
       
   124 			iSocket.RecvFrom(iPacket, iAddress, 0, iStatus);
       
   125 			//is this the last packet to be received? 
       
   126 			if(iState==ESendingLastData) iState = EReceivingLast;
       
   127 			else iState = EReceiving;
       
   128 			//start timer for timeout and set object active
       
   129 			iTimer->After(iTimeOut);
       
   130 			SetActive();
       
   131 			}
       
   132 
       
   133 		else if(iState==EReceiving||iState==EReceivingLast)
       
   134             //received packet, determine opcode and behave accordingly
       
   135 			{
       
   136 			switch(iPacket.OpCode())
       
   137 				{
       
   138             case EDATA: //DATA packet
       
   139                 if (!iPacket.CheckBlock()) break;
       
   140                 else
       
   141                     //write data to file and make ackn packet
       
   142                     {
       
   143                     if(iFile.Write(iPacket.Mid(4))!=KErrNone)  //Error, bail out.
       
   144 						{
       
   145 						iFile.Close();
       
   146 						iState = EComplete;
       
   147 						iNotifier.OpComplete(EError, 0);
       
   148 						break;
       
   149 						}
       
   150                     iNotifier.ProgressNotification();
       
   151                     if (iPacket.Size()<516)
       
   152                         //this is the last packet  
       
   153                         {
       
   154                         iFile.Close();
       
   155                         iState = ESendingLastAckn;
       
   156                         }
       
   157                     else 
       
   158                         iState = ESending;
       
   159                     //now make the ackn. packet
       
   160                     iPacket.MakeAckn();
       
   161                     }
       
   162                 break;
       
   163 
       
   164             case EACK: // ACKN. packet
       
   165                 if (!iPacket.CheckBlock()) break;
       
   166                 else if (iState == EReceiving)
       
   167                     {
       
   168                     iNotifier.ProgressNotification();
       
   169                     //more data to be sent
       
   170                     TBuf8<512> data;
       
   171                     if(iFile.Read(data)!=KErrNone)	//Error, bail out.
       
   172 						{
       
   173 						iFile.Close();
       
   174 						iState = EComplete;
       
   175 						iNotifier.OpComplete(EError, 0);
       
   176 						break;
       
   177 						}
       
   178                     if(iPacket.MakeData(data)<516) 
       
   179                         //this is the last data packet to be sent
       
   180                         {
       
   181                         iFile.Close();
       
   182                         iState=ESendingLastData;
       
   183                         }
       
   184                     else
       
   185                         iState=ESending;
       
   186                     }
       
   187                 else
       
   188                     //this was the final ackn., no more data to be sent
       
   189                     {
       
   190                     iState = EComplete;
       
   191                     iNotifier.OpComplete(EOpComplete, 0);
       
   192                     }
       
   193                 break;
       
   194 
       
   195             case EERR: //ERROR packet
       
   196                 //ERROR: Terminate (implement later)
       
   197                 iState = EComplete;
       
   198                 iNotifier.OpComplete(EError, 0);
       
   199                 break;
       
   200 
       
   201             default:
       
   202                 //OpCode should never be anything other than 3, 4 
       
   203                 //or 5 so something screwy happened: terminate
       
   204                 iState = EComplete;
       
   205                 iNotifier.OpComplete(EError, 0);
       
   206                 break;
       
   207 				}
       
   208 
       
   209 			if(iState != EComplete)
       
   210 				if (iState==EReceiving||iState==EReceivingLast)
       
   211                     //block number incorrect, repeat the receive from
       
   212 					{
       
   213 					iSocket.RecvFrom(iPacket, iAddress, 0, iStatus);
       
   214 					iTimer->After(iTimeOut);
       
   215 					SetActive();
       
   216 					}
       
   217 				else
       
   218                     //send the packet constructed in above SWITCH statement
       
   219 					{
       
   220 					iSocket.SendTo(iPacket, iAddress, 0, iStatus);
       
   221 					iTimer->After(iTimeOut);
       
   222 					SetActive();
       
   223 					}
       
   224 			}
       
   225 		}	
       
   226 	}
       
   227 
       
   228 void CTftpEngine::DoCancel()
       
   229 //
       
   230 // Cancel what ever is happening
       
   231 //
       
   232     {
       
   233 	if (iState == ESending||iState == ESendingLastData||
       
   234 		iState == ESendingLastAckn) 
       
   235 		iSocket.CancelSend();
       
   236 	else if (iState == EReceiving||iState == EReceivingLast)
       
   237 		iSocket.CancelRecv();
       
   238 	//set state to complete. may replace with error code later
       
   239 	iState = EComplete;
       
   240 	iFile.Close();
       
   241 	}
       
   242 
       
   243 EXPORT_C CTftpEngine* CTftpEngine::NewL(const TInt aPriority, MTftpNotifier& aNotifier)
       
   244 //
       
   245 // Create and connect client with leaving
       
   246 //
       
   247     {
       
   248     CTftpEngine *p = new (ELeave) CTftpEngine(aPriority, aNotifier);
       
   249     CleanupStack::PushL(p);
       
   250     p->ConstructL();
       
   251     CleanupStack::Pop(p);
       
   252     return p;
       
   253     }
       
   254 
       
   255 //**********************************************
       
   256 //
       
   257 //	The Methods for the class CTftpTimer:
       
   258 //
       
   259 //**********************************************
       
   260 
       
   261 CTftpTimer::CTftpTimer(const TInt aPriority, CTftpEngine& aEngine)
       
   262     : CTimer(aPriority), iEngine(aEngine)
       
   263 //
       
   264 // C++ C'tor
       
   265 //
       
   266     {
       
   267     CActiveScheduler::Add(this);
       
   268     }
       
   269 
       
   270 CTftpTimer::~CTftpTimer()
       
   271 //
       
   272 // C++ D'tor
       
   273 //
       
   274     {
       
   275 	Cancel();
       
   276     }
       
   277 
       
   278 void CTftpTimer::ConstructL()
       
   279 //
       
   280 // E32 C'tor
       
   281 //
       
   282     {
       
   283 	CTimer::ConstructL();
       
   284     }
       
   285 
       
   286 void CTftpTimer::RunL()
       
   287 //
       
   288 // Run method where all the action happens
       
   289 //
       
   290     {
       
   291 	iEngine.TimerExpired();
       
   292 	}
       
   293 
       
   294 CTftpTimer* CTftpTimer::NewL(const TInt aPriority, CTftpEngine& aEngine)
       
   295 //
       
   296 // Create and connect client with leaving
       
   297 //
       
   298     {
       
   299     CTftpTimer *p = new (ELeave) CTftpTimer(aPriority, aEngine);
       
   300     CleanupStack::PushL(p);
       
   301 	p->ConstructL();
       
   302 	CleanupStack::Pop(p);
       
   303     return p;
       
   304     }
       
   305 
       
   306 //**********************************************
       
   307 //
       
   308 //	The Methods for the class TTftpPacket:
       
   309 //
       
   310 //**********************************************
       
   311 
       
   312 TTftpPacket::TTftpPacket()
       
   313     : TPtr8(iBuffer,2,516),iBlockNum(0)
       
   314     {
       
   315     }
       
   316 
       
   317 TBool TTftpPacket::CheckBlock()
       
   318 	{
       
   319 	//if the block numbers do not match then return false
       
   320 	if (BigEndian::Get16(&iBuffer[2])!=iBlockNum) 
       
   321 		return EFalse;
       
   322 	//otherwise, increment block num. for next packet and return true
       
   323 	iBlockNum++;
       
   324 	return ETrue;
       
   325 	}
       
   326 
       
   327 void TTftpPacket::MakeRqst(const TOpCode aOpc, const TDesC& aName, const TDesC& aMode)
       
   328 	{
       
   329 	TChar null = 0;
       
   330 	//initialize block no. for this transfer
       
   331 	if (aOpc == ERRQ) 
       
   332 		iBlockNum = 1;
       
   333 	else 
       
   334 		iBlockNum = 0;
       
   335 	//make the request packet
       
   336 	SetLength(2);
       
   337 	BigEndian::Put16(iBuffer, (TUint16)aOpc);
       
   338 	Append(aName);
       
   339 	Append(null);
       
   340 	Append(aMode);
       
   341 	Append(null);
       
   342 	}
       
   343 
       
   344 TInt TTftpPacket::OpCode()
       
   345 	{
       
   346 	//return OpCode from packet
       
   347 	return (TInt)BigEndian::Get16(iBuffer);
       
   348 	}
       
   349 
       
   350 void TTftpPacket::MakeAckn()
       
   351 	{
       
   352 	//make an ackn. packet
       
   353 	SetLength(4);
       
   354 	BigEndian::Put16(iBuffer, (TUint16)4);
       
   355 	}
       
   356 
       
   357 TInt TTftpPacket::MakeData(const TDesC8& aData)
       
   358 	{
       
   359 	//make a data packet using data supplied
       
   360 	SetLength(4);
       
   361 	BigEndian::Put16(iBuffer, (TUint16)3);
       
   362 	BigEndian::Put16(&iBuffer[2], (TUint16)iBlockNum);
       
   363 	Append(aData);
       
   364 	return Size();	
       
   365 	}
       
   366 
       
   367 void TTftpPacket::MakeError()
       
   368 	{
       
   369 	//not implemented 
       
   370 	}
       
   371