engine.cpp
上传用户:sempras
上传日期:2007-03-04
资源大小:821k
文件大小:15k
- ////////////////////////////////////////////////////////////////
- //
- // engine.cpp
- //
- // Copyright (C) 2001, Forum Nokia - The Developer Community
- //
- //
- ////////////////////////////////////////////////////////////////
- #include <e32base.h>
- #include "tcpudp.h"
- #include "engine.h"
- const TInt KTimeOut = 15000000; // 30 seconds time-out
- /**************************************************
- Class constructor
- **************************************************/
- CRunEngine::CRunEngine(): CActive(EPriorityHigh), iRecData(0,0), iSendData(0,0)
- {
- }
- /*************************************************/
- /**************************************************
- Class destructor
- **************************************************/
- CRunEngine::~CRunEngine()
- {
- Cancel();
- iSocketServer.Close();
- if (iRecBuffer != 0)
- {
- delete iRecBuffer;
- iRecBuffer = 0;
- }
- if (iSendBuffer != 0)
- {
- delete iSendBuffer;
- iSendBuffer = 0;
- }
- delete iMyTimer;
- }
- /**************************************************/
- /**************************************************
- Second phase constructor
- **************************************************/
- void CRunEngine::ConstructL(CTcpUdpView *aAppView)
- {
- iAppView = aAppView;
- iSendBuffer = 0;
- iRecBuffer = 0;
-
- iState = EIdle;
- CActiveScheduler::Add(this); //Adds itself to the scheduler
- //Default values
- TPreferences preferences;
- DefaultPreferences(preferences);
-
- iProtocol = preferences.iProtocol;
- iRemotePort = preferences.iRemotePort;
- iRemoteAddr.Copy(preferences.iRemoteAddr);
-
- iLocalPort = preferences.iLocalPort;
- iLocalAddr.Copy(preferences.iLocalAddr);
-
- iCount = preferences.iCount;
- iTrace = preferences.iTrace;
- iPacketSize = preferences.iPacketSize;
-
- // Timer
- iMyTimer = new(ELeave) CMyTimer;
- iMyTimer->ConstructL(this);
- /*
- The client has to open a session with the ESOCK server by
- calling the Connect() method of the RSocketServ class. The
- connected socket server will be used later in the Start()
- method for opening a socket.
- */
-
- // Connect() may leave
- CleanupStack::PushL(iMyTimer);
- TInt err = iSocketServer.Connect();
- if (err != KErrNone)
- {
- User::Panic(_L("Cannot open session with the ESOCK server!"), err);
- }
- CleanupStack::Pop();
- }
- /*************************************************/
- /**************************************************
- Function: specifies default values
- **************************************************/
- void CRunEngine::DefaultPreferences(TPreferences &aPref)
- {
- //Default values
- aPref.iProtocol = UDP;
- aPref.iRemotePort = 7;
- aPref.iRemoteAddr = _L("127.0.0.1");
- aPref.iLocalPort = 2080;
- aPref.iLocalAddr = _L("127.0.0.1");
- aPref.iCount = 1000;
- aPref.iTrace = EFalse ;
- aPref.iPacketSize = 10 ;
- }
- /*************************************************/
- /**************************************************
- Function: passes current setting values
- **************************************************/
- void CRunEngine::GetPreferences(TPreferences &aPref)
- {
- aPref.iProtocol = iProtocol;
- aPref.iRemotePort = iRemotePort;
- aPref.iRemoteAddr.Copy(iRemoteAddr);
- aPref.iLocalPort = iLocalPort;
- aPref.iLocalAddr.Copy(iLocalAddr) ;
- aPref.iCount = iCount;
- aPref.iTrace = iTrace;
- aPref.iPacketSize = iPacketSize;
- }
- /*************************************************/
- /**************************************************
- Function: sets new setting values
- **************************************************/
- void CRunEngine::SetPreferences(TPreferences &aPref)
- {
- iProtocol = aPref.iProtocol;
- iRemotePort = aPref.iRemotePort;
- iRemoteAddr.Copy(aPref.iRemoteAddr) ;
- iLocalPort = aPref.iLocalPort;
- iLocalAddr.Copy(aPref.iLocalAddr);
- iCount = aPref.iCount;
- iTrace = aPref.iTrace;
- iPacketSize = aPref.iPacketSize;
- }
- /*************************************************/
- /**************************************************
- Function: starts the sending/receiving process
- **************************************************/
- TInt CRunEngine::Start()
- {
- TInt err = KErrNone;
- if (iPacketSize == 0)
- iPacketSize = 1;
-
- if (iSendBuffer != 0)
- delete iSendBuffer;
-
- // Create the sent packet with 1 extra byte for zero terminate
- iSendBuffer = HBufC8::NewL(iPacketSize+1);
- iSendData.Set(iSendBuffer->Des());
- // Initialize send data buffer
- iSendData.FillZ();
- iSendData.Zero();
- // dummy character in sending packet
- TChar xChar = 'X';
- // just fill the packet with dummy characters
- iSendData.Fill(xChar, iPacketSize-1);
- // Currently the Echoserver reads coming data till it receives a
- // newline character. This is recognized as the end of each packet.
- TChar nl = 'n';
- iSendData.Append(nl);
- iSendData.ZeroTerminate();
- if (iRecBuffer != 0)
- delete iRecBuffer ;
- /*
- Because the echoserver will send back the same data with the same
- size, we create a received buffer with its length is equal to
- the sent packet's size. Otherwise the size can be arbitrarily set.
- */
- // Allocate memory for the receiving buffer
- iRecBuffer = HBufC8::NewL(iPacketSize+1);
- TPtr8 auxPtr(( TUint8* )iRecBuffer->Des().Ptr(), iPacketSize);
- iRecData.Set(auxPtr);
-
- // reset other necessary parameters
- iState = EIdle;
- iRecvPackets = 0;
- iSentPackets = 0;
- iTotalBytesRcvd = 0;
- /*
- Initialize the remote host parameters by setting its
- port and IP address
- */
- iSendAddr.SetPort(iRemotePort); // remote port
- iSendAddr.Input(iRemoteAddr) ; // remote address
- // set the local port
- iRecAddr.SetPort(iLocalPort); // own port
- // make sure address family is correct
- if (iSendAddr.Family() == KAfInet)
- {
- // own address IPv4
- iRecAddr.Input(iLocalAddr) ;
- iAppView->Write(_L("nUsing IPv4 addresses."));
- }
- // this sample application does not support IPv6 address
- else
- {
- iAppView->Write(_L("nNot support IP type."));
- return -1;
- }
- /*
- open a socket according to protocol type for sending/receiving data
- */
- if (iProtocol == TCP)
- err = iSocket.Open( iSocketServer, // The socket server session
- KAfInet, // Constant for a protocol family
- KSockStream, // Stream socket
- KProtocolInetTcp // Constant which identifies the TCP protocol
- );
- else
- err = iSocket.Open( iSocketServer, // The socket server session
- KAfInet, // Constant for a protocol family
- KSockDatagram, // Datagram socket
- KProtocolInetUdp // Constant which identifies the UDP protocol
- );
-
- // checking Open()'s returned value
- if (err != KErrNone)
- {
- iAppView->Write(_L("Cannot open the socket!.n"));
- return err;
- }
- /*
- setting the local port is equivalent to calling Bind() with
- only the port set in the address.
- */
- err = iSocket.SetLocalPort(iLocalPort);
- if (err != KErrNone)
- {
- if (err == KErrInUse)
- iAppView->Write(_L("nLocal port is in use.n"));
- else
- iAppView->Write(_L("Socket binding failed.n"));
- return err;
- }
- /*
- For TCP sockets, an active connection is made to the remote
- host. When the socket call completes successfully, the socket
- is ready to send and receive data. To form a connection,
- the protocol must establish a network interface and a route
- to the destination. So the Connect() method is called.
- */
- if (iProtocol == TCP)
- {
- __ASSERT_ALWAYS(!IsActive(), User::Panic(_L("CRunEngine"), 1));
- // Connect
- iSocket.Connect(iSendAddr, iStatus);
- SetActive();
-
- TBuf<80> aux;
- aux.Format(_L("nConnecting to port %d.n"), iRemotePort);
- iAppView->Write(aux);
- iState = EConnected;
- }
- /*
- As UDP is a connectionless protocol, Connect() does not have to
- be called before writing data with RSocket::SendTo(). However,
- even for UDP Connect() can be also used to set the address for
- all data sent from the socket, in which case Send()/Write() may
- be used in addition to SendTo().
- In this example, SendTo() is employed so Connect() is not called
- */
- else // UDP
- {
- TBuf<80> aux;
- aux.Format(_L("nSending UDP packets to port %d.n"), iRemotePort);
- iAppView->Write(aux);
- SendPacket();
- iState = ESending;
- }
- return KErrNone;
- }
- /*************************************************/
- /**************************************************
- Function: cancels any socket pending process
- **************************************************/
- void CRunEngine::Stop()
- {
- TBuf<80> aux;
- aux.Format(_L("Total number of sent packets: %d.n"), iSentPackets);
- iAppView->Write(aux);
- // Cancel() will cause a call to DoCancel() which
- // cancels any outstanding read/write operation.
- Cancel();
- iStatus = KErrNone;
- iState = EClosing;
- RunL();
- if (iSendBuffer != 0)
- {
- delete iSendBuffer ;
- iSendBuffer = 0 ;
- }
- if (iRecBuffer != 0)
- {
- delete iRecBuffer ;
- iRecBuffer = 0 ;
- }
- }
- /*************************************************/
- /**************************************************
- Function: handles the engine active object抯
- request completion event.
- **************************************************/
- void CRunEngine::RunL()
- {
- // holding information message to print on the screen
- TBuf<80> aux;
- if (iStatus == KErrCancel || iStatus == KErrAbort)
- { // This happens after calling cancel functions in socket
- iStatus = KErrNone;
- }
- else if (iStatus != KErrNone)
- {
- iAppView->Write(_L("Something happened.n"));
- aux.Format(_L("RunL received iStatus = %d.n"),iStatus);
- iAppView->Write(aux);
- CloseSockets();
- iState = EIdle;
- iAppView->UpdateBusyMsg();
- }
- /*
- The asynchronous operation that has completed and we
- check the current state of communication action.
- iState was set to engage the engine to one of the
- following states:
- */
- else switch (iState)
- {
- // Idle status, nothing to send or receive
- case EIdle:
- break;
- // TCP connection is established
- case EConnected:
- iAppView->Write(_L("Connected.n"));
- // Start sending the first packet
- SendPacket();
- break;
- // a packet has been sent out
- case ESending:
- // increment the number of sent packets
- iSentPackets++ ;
- if (iTrace)
- {
- aux.Format(_L("Sent packet number %d.n"), iSentPackets);
- iAppView->Write(aux);
- }
- /*
- after a packet is sent, an echo packet is expected
- from the echoserver. ReceivePacket() will issue a
- read/recv request and wait for a reply
- */
- ReceivePacket();
- // set the timer to timeout after 15 sec if the reply from
- // the echoserver does not come.
- if (iProtocol == UDP)
- if (!iMyTimer->IsActive())
- iMyTimer->After(KTimeOut); // 15 sec
- // Prevent inactivity-related events from occuring (blank screen)
- User::ResetInactivityTime() ;
- break;
-
- // a reply (echoed) packet has come
- case EReceiving:
- // if the reply comes while timeout is pending,
- // the timer must be cancelled
- if (iMyTimer->IsActive())
- iMyTimer->Cancel() ;
- // increment the number of received packets
- iRecvPackets++;
-
- if (iTrace)
- {
- iTotalBytesRcvd += iRecData.Length();
- aux.Format(_L("Received %d bytes. Total %d.n"),iRecData.Length(), iTotalBytesRcvd);
- iAppView->Write(aux);
- }
- /*
- iCount is the number of packets to be sent set by a user,
- if iCount is 0, the loop is infinity, otherwise, sending
- loop terminates when the number of echoed packets is equal
- to the value of iCount
- */
- if ( (iCount > 0) && (iRecvPackets >= iCount) )
- {
- Stop();
- break;
- }
-
- // call to send next packet
- SendPacket();
- break;
- // when the Stop button is clicked or all echoed packets are received
- case EClosing:
- // close the connected socket
- CloseSockets();
- iState = EIdle;
- iAppView->Write(_L("TcpUdp stopped.n"));
- iAppView->UpdateBusyMsg();
- break;
- // any undefined state
- default:
- iAppView->Write(_L("Something is wrong, State unknown.n"));
- iState = EIdle;
- break;
- }
- }
- /*************************************************/
- /**************************************************
- Function: asynchronously reads/receives incoming
- data from the socket.
- **************************************************/
- void CRunEngine::ReceivePacket()
- {
- iRecData.Zero();
- if (iProtocol == TCP)
- {
- iSocket.Recv(iRecData, 0, iStatus, iNumRcvd);
- }
- else // UDP
- iSocket.RecvFrom(iRecData, iRecAddr, 0, iStatus);
- iState = EReceiving;
- SetActive();
- }
- /*************************************************/
- /**************************************************
- Function: handles the engine active object抯
- request completion event.
- **************************************************/
- void CRunEngine::SendPacket()
- {
- if (iProtocol == TCP)
- iSocket.Send(iSendData, 0, iStatus, iNumRcvd);
- else // UDP
- iSocket.SendTo(iSendData, iSendAddr, 0, iStatus);
- // engage the engine to sending
- iState = ESending;
- SetActive();
- }
- /*************************************************/
- /**************************************************
- Function: releases the local port then
- close the socket.
- **************************************************/
- void CRunEngine::CloseSockets()
- {
- // This ensures that TCP releases local port at once
- iSocket.CancelConnect();
- iSocket.Close();
- }
- /*************************************************/
- /**************************************************
- Function: cancels outstanding operations then
- close the socket.
- **************************************************/
- void CRunEngine::DoCancel()
- {
- if (iMyTimer->IsActive())
- iMyTimer->Cancel() ;
-
-
- switch (iState)
- {
- case EIdle:
- case EClosing:
- break;
- // cancel any asynchronous operations.
- case EConnected:
- iSocket.CancelAll();
- break;
- // cancel an outstanding receive operation.
- case EReceiving:
- iSocket.CancelRecv();
- break;
- // cancel an outstanding send operation
- case ESending:
- iSocket.CancelSend();
- break;
- default:
- iAppView->Write(_L("Something is really wrong, State unknown.n"));
- iSocket.CancelAll();
- iState = EIdle;
- }
- }
- //
- // class CMyTimer
- //
- CMyTimer::CMyTimer(): CTimer(0)
- {}
- void CMyTimer::ConstructL(CRunEngine *aEngine)
- {
- CTimer::ConstructL();
- CActiveScheduler::Add(this);
- iEngine = aEngine;
- }
- void CMyTimer::RunL()
- {
- // if timer timeouts, call Stop() to cancel any
- // outstanding operation and retry by calling Start()
- iEngine->Stop();
- iEngine->Start();
- }