--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networkingtestandutils/exampleinternetutilities/TFTPENG/TFTPENG.CPP Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,371 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// TftpEngine.CPP
+// Started by AY, May 1997
+//
+//
+
+#include <tftpeng.h>
+
+EXPORT_C CTftpEngine::~CTftpEngine()
+ {
+ Cancel();
+ iSocket.Close();
+ iSockServ.Close();
+ iFs.Close();
+ delete iTimer;
+ }
+
+CTftpEngine::CTftpEngine(const TInt aPriority, MTftpNotifier& aNotifier)
+ : CActive(aPriority), iNotifier(aNotifier)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CTftpEngine::ConstructL()
+ {
+ iTimer = CTftpTimer::NewL(10, *this);
+ iTimeOut = 30000000;
+ iAddress.SetPort(5001); //Arbitrary port
+ User::LeaveIfError(iSockServ.Connect());
+ User::LeaveIfError(iSocket.Open(iSockServ, KAfInet, KSockDatagram, KProtocolInetUdp));
+ iSocket.Bind(iAddress);
+ User::LeaveIfError(iFs.Connect());
+ }
+
+EXPORT_C void CTftpEngine::Get(const TDesC& aNetAddr, const TDesC& aName, const TDesC& aMode)
+ {
+ //send Get rqst. to given address, port 69 (TFTP standard)
+ iAddress.SetPort(69);
+ iAddress.Input(aNetAddr);
+ if (iFile.Replace(iFs, aName, EFileWrite|EFileShareAny) != KErrNone)
+ iNotifier.OpComplete(EFileOpenFailure, 0);
+ else
+ {
+ iPacket.MakeRqst(ERRQ, aName, aMode);
+ iSocket.SendTo(iPacket, iAddress, 0, iStatus);
+ iState = ESending;
+ //start timer for rqst.
+ iTimer->After(iTimeOut);
+ SetActive();
+ }
+ }
+
+EXPORT_C void CTftpEngine::Put(const TDesC& aNetAddr, const TDesC& aName, const TDesC& aMode)
+ {
+ //send Put rqst. to given address, port 69 (TFTP standard)
+ iAddress.SetPort(69);
+ iAddress.Input(aNetAddr);
+ if (iFile.Open(iFs, aName, EFileRead|EFileShareAny) != KErrNone)
+ iNotifier.OpComplete(EFileOpenFailure, 0);
+ else
+ {
+ iPacket.MakeRqst(EWRQ, aName, aMode);
+ iSocket.SendTo(iPacket, iAddress, 0, iStatus);
+ iState = ESending;
+ //start timer for rqst.
+ iTimer->After(iTimeOut);
+ SetActive();
+ }
+ }
+
+EXPORT_C void CTftpEngine::TimerExpired()
+ {
+ Cancel();
+ iNotifier.OpComplete(ETimedOut, 0);
+ }
+
+EXPORT_C void CTftpEngine::SetTimeOut(const TInt aTimeOut)
+ {
+ iTimeOut = aTimeOut;
+ }
+
+void CTftpEngine::RunL()
+ {
+ //cancel Timer immediately to avoid unwanted timeouts
+ iTimer->Cancel();
+
+ if (iStatus!=KErrNone)
+ //the send/recv completed with an error: Terminate
+ {
+ //NOTE:must check for other states too (e.g. ESendingLastData)
+ if(iState==ESending)
+ iNotifier.OpComplete(ESendFail, 0);
+ else if(iState==EReceiving)
+ iNotifier.OpComplete(ERecvFail, 0);
+ else
+ iNotifier.OpComplete(EError, 0); //temp. cover for other states
+ iState = EComplete;
+ }
+
+ else
+ {
+ if(iState==ESendingLastAckn)
+ //transfer completed successfully: Notify
+ {
+ iState = EComplete;
+ iNotifier.OpComplete(EOpComplete, 0);
+ }
+
+ else if(iState==ESending||iState==ESendingLastData)
+ //send successful, collect reply
+ {
+ iSocket.RecvFrom(iPacket, iAddress, 0, iStatus);
+ //is this the last packet to be received?
+ if(iState==ESendingLastData) iState = EReceivingLast;
+ else iState = EReceiving;
+ //start timer for timeout and set object active
+ iTimer->After(iTimeOut);
+ SetActive();
+ }
+
+ else if(iState==EReceiving||iState==EReceivingLast)
+ //received packet, determine opcode and behave accordingly
+ {
+ switch(iPacket.OpCode())
+ {
+ case EDATA: //DATA packet
+ if (!iPacket.CheckBlock()) break;
+ else
+ //write data to file and make ackn packet
+ {
+ if(iFile.Write(iPacket.Mid(4))!=KErrNone) //Error, bail out.
+ {
+ iFile.Close();
+ iState = EComplete;
+ iNotifier.OpComplete(EError, 0);
+ break;
+ }
+ iNotifier.ProgressNotification();
+ if (iPacket.Size()<516)
+ //this is the last packet
+ {
+ iFile.Close();
+ iState = ESendingLastAckn;
+ }
+ else
+ iState = ESending;
+ //now make the ackn. packet
+ iPacket.MakeAckn();
+ }
+ break;
+
+ case EACK: // ACKN. packet
+ if (!iPacket.CheckBlock()) break;
+ else if (iState == EReceiving)
+ {
+ iNotifier.ProgressNotification();
+ //more data to be sent
+ TBuf8<512> data;
+ if(iFile.Read(data)!=KErrNone) //Error, bail out.
+ {
+ iFile.Close();
+ iState = EComplete;
+ iNotifier.OpComplete(EError, 0);
+ break;
+ }
+ if(iPacket.MakeData(data)<516)
+ //this is the last data packet to be sent
+ {
+ iFile.Close();
+ iState=ESendingLastData;
+ }
+ else
+ iState=ESending;
+ }
+ else
+ //this was the final ackn., no more data to be sent
+ {
+ iState = EComplete;
+ iNotifier.OpComplete(EOpComplete, 0);
+ }
+ break;
+
+ case EERR: //ERROR packet
+ //ERROR: Terminate (implement later)
+ iState = EComplete;
+ iNotifier.OpComplete(EError, 0);
+ break;
+
+ default:
+ //OpCode should never be anything other than 3, 4
+ //or 5 so something screwy happened: terminate
+ iState = EComplete;
+ iNotifier.OpComplete(EError, 0);
+ break;
+ }
+
+ if(iState != EComplete)
+ if (iState==EReceiving||iState==EReceivingLast)
+ //block number incorrect, repeat the receive from
+ {
+ iSocket.RecvFrom(iPacket, iAddress, 0, iStatus);
+ iTimer->After(iTimeOut);
+ SetActive();
+ }
+ else
+ //send the packet constructed in above SWITCH statement
+ {
+ iSocket.SendTo(iPacket, iAddress, 0, iStatus);
+ iTimer->After(iTimeOut);
+ SetActive();
+ }
+ }
+ }
+ }
+
+void CTftpEngine::DoCancel()
+//
+// Cancel what ever is happening
+//
+ {
+ if (iState == ESending||iState == ESendingLastData||
+ iState == ESendingLastAckn)
+ iSocket.CancelSend();
+ else if (iState == EReceiving||iState == EReceivingLast)
+ iSocket.CancelRecv();
+ //set state to complete. may replace with error code later
+ iState = EComplete;
+ iFile.Close();
+ }
+
+EXPORT_C CTftpEngine* CTftpEngine::NewL(const TInt aPriority, MTftpNotifier& aNotifier)
+//
+// Create and connect client with leaving
+//
+ {
+ CTftpEngine *p = new (ELeave) CTftpEngine(aPriority, aNotifier);
+ CleanupStack::PushL(p);
+ p->ConstructL();
+ CleanupStack::Pop(p);
+ return p;
+ }
+
+//**********************************************
+//
+// The Methods for the class CTftpTimer:
+//
+//**********************************************
+
+CTftpTimer::CTftpTimer(const TInt aPriority, CTftpEngine& aEngine)
+ : CTimer(aPriority), iEngine(aEngine)
+//
+// C++ C'tor
+//
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CTftpTimer::~CTftpTimer()
+//
+// C++ D'tor
+//
+ {
+ Cancel();
+ }
+
+void CTftpTimer::ConstructL()
+//
+// E32 C'tor
+//
+ {
+ CTimer::ConstructL();
+ }
+
+void CTftpTimer::RunL()
+//
+// Run method where all the action happens
+//
+ {
+ iEngine.TimerExpired();
+ }
+
+CTftpTimer* CTftpTimer::NewL(const TInt aPriority, CTftpEngine& aEngine)
+//
+// Create and connect client with leaving
+//
+ {
+ CTftpTimer *p = new (ELeave) CTftpTimer(aPriority, aEngine);
+ CleanupStack::PushL(p);
+ p->ConstructL();
+ CleanupStack::Pop(p);
+ return p;
+ }
+
+//**********************************************
+//
+// The Methods for the class TTftpPacket:
+//
+//**********************************************
+
+TTftpPacket::TTftpPacket()
+ : TPtr8(iBuffer,2,516),iBlockNum(0)
+ {
+ }
+
+TBool TTftpPacket::CheckBlock()
+ {
+ //if the block numbers do not match then return false
+ if (BigEndian::Get16(&iBuffer[2])!=iBlockNum)
+ return EFalse;
+ //otherwise, increment block num. for next packet and return true
+ iBlockNum++;
+ return ETrue;
+ }
+
+void TTftpPacket::MakeRqst(const TOpCode aOpc, const TDesC& aName, const TDesC& aMode)
+ {
+ TChar null = 0;
+ //initialize block no. for this transfer
+ if (aOpc == ERRQ)
+ iBlockNum = 1;
+ else
+ iBlockNum = 0;
+ //make the request packet
+ SetLength(2);
+ BigEndian::Put16(iBuffer, (TUint16)aOpc);
+ Append(aName);
+ Append(null);
+ Append(aMode);
+ Append(null);
+ }
+
+TInt TTftpPacket::OpCode()
+ {
+ //return OpCode from packet
+ return (TInt)BigEndian::Get16(iBuffer);
+ }
+
+void TTftpPacket::MakeAckn()
+ {
+ //make an ackn. packet
+ SetLength(4);
+ BigEndian::Put16(iBuffer, (TUint16)4);
+ }
+
+TInt TTftpPacket::MakeData(const TDesC8& aData)
+ {
+ //make a data packet using data supplied
+ SetLength(4);
+ BigEndian::Put16(iBuffer, (TUint16)3);
+ BigEndian::Put16(&iBuffer[2], (TUint16)iBlockNum);
+ Append(aData);
+ return Size();
+ }
+
+void TTftpPacket::MakeError()
+ {
+ //not implemented
+ }
+