EchoClientEngine
: TCP/IP echo client engine
Found in: examples\Networking\TcpIp\EchoClientEngine
These are the main files contained in the examples. Some extra files may be needed to run the examples, and these will be found in the appropriate examples directory.
// Copyright (c) 2000-2005 Symbian Software Ltd. All rights reserved.
//
//
// Echoeng.cpp
//
// Defines CEchoEngine, CEchoRead, CEchoWrite, CTimeOutTimer
#include "echoeng.h"
// 50 seconds time-out
const TInt KTimeOut = 50000000;
/*
CEchoEngine: main engine class for connection and shutdown
*/
EXPORT_C CEchoEngine::CEchoEngine() : CActive(EPriorityStandard)
{
}
EXPORT_C CEchoEngine* CEchoEngine::NewL(MUINotify* aConsole)
{
CEchoEngine* self = NewLC(aConsole);
CleanupStack::Pop();
return self;
}
EXPORT_C CEchoEngine* CEchoEngine::NewLC(MUINotify* aConsole)
{
CEchoEngine* self = new(ELeave) CEchoEngine;
CleanupStack::PushL(self);
self->ConstructL(aConsole);
return self;
}
/*
Constructs object, and opens a socket
*/
EXPORT_C void CEchoEngine::ConstructL(MUINotify* aConsole)
{
iConsole = aConsole;
iEngineStatus = EComplete;
iTimeOut = KTimeOut;
iTimer = CTimeOutTimer::NewL(EPriorityHigh, *this);
CActiveScheduler::Add(this);
// Open channel to Socket Server
User::LeaveIfError(iSocketServ.Connect());
// Open a TCP socket
User::LeaveIfError(iEchoSocket.Open(iSocketServ, KAfInet, KSockStream, KProtocolInetTcp));
iEchoRead = CEchoRead::NewL(&iEchoSocket, aConsole);
iEchoWrite = CEchoWrite::NewL(&iEchoSocket, aConsole);
}
void CEchoEngine::DoCancel()
// Cancel asychronous requests
{
iTimer->Cancel();
// Cancel appropriate request to socket
switch (iEngineStatus)
{
case EConnecting:
iEchoSocket.CancelConnect();
break;
case ELookingUp:
// Cancel look up attempt
iResolver.Cancel();
iResolver.Close();
break;
default:;
}
}
/*
Connect to an Echo Socket by IP address
*/
EXPORT_C void CEchoEngine::ConnectL(TUint32 aAddr)
{
// port number for test purposes - may need to be changed
iAddress.SetPort(7);
iAddress.SetAddress(aAddr);
iEchoSocket.Connect(iAddress, iStatus);
iEngineStatus = EConnecting;
SetActive();
iTimer->After(iTimeOut);
}
EXPORT_C void CEchoEngine::ConnectL(const TDesC& aServerName)
// Connect to an Echo socket by hostname
{
// Initiate DNS
User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp));
// DNS request for name resolution
iResolver.GetByName(aServerName, iNameEntry, iStatus);
iEngineStatus=ELookingUp;
// Request time out
iTimer->After(iTimeOut);
SetActive();
}
EXPORT_C void CEchoEngine::TestGetByAddr(TUint32 aAddr)
// Looks up hostname, and then connects to an Echo socket
{
// Initiate DNS
User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp));
// DNS request for address lookup
iAddress.SetAddress(aAddr);
iResolver.GetByAddress(iAddress, iNameEntry, iStatus);
iEngineStatus=ELookingUp;
// Request time out
iTimer->After(iTimeOut);
SetActive();
}
/*
Exported function wrapping call to CEchoWrite: writes character to socket
*/
EXPORT_C void CEchoEngine::Write(TChar aChar)
{
/*
In this simple implementation, if iEchoWrite is already active, ignore call.
Full implementation would buffer data
*/
if ((iEngineStatus == EConnected) && !iEchoWrite->IsActive())
iEchoWrite->IssueWrite(aChar);
}
/*
Exported function wrapping call to CEchoRead: reads character from socket
*/
EXPORT_C void CEchoEngine::Read()
{
if ((iEngineStatus == EConnected)&&(!iEchoRead->IsActive()))
iEchoRead->IssueRead();
}
/*
Active object request complete handler.
iEngineStatus flags what request was made, so its
completion can be handled appropriately
*/
void CEchoEngine::RunL()
{
// Cancel TimeOut timer before completion
iTimer->Cancel();
_LIT(KConnecting,"\n<CEchoEngine> Connecting\n");
_LIT(KConnectionFailed,"\n<CEchoEngine> Connection failed");
_LIT(KDNSFailed,"\n<CEchoEngine> DNS lookup failed");
_LIT(KTimedOut,"\n<CEchoEngine> Timed out\n");
_LIT(KDomainName,"\nDomain name = ");
_LIT(KIPAddress,"\nIP address = ");
TBuf<15> ipAddr;
switch(iEngineStatus)
{
case EConnecting:
// IP connection request
if (iStatus == KErrNone)
// Connection completed sucessfully
{
iConsole->PrintNotify(KConnecting);
iEngineStatus = EConnected;
//Start CEchoRead Active object
Read();
}
else
{
iEngineStatus = EConnectFailed;
iConsole->ErrorNotify(KConnectionFailed, iStatus.Int());
}
break;
case ETimedOut:
// Timeout request
iConsole->ErrorNotify(KTimedOut, KErrTimedOut);
break;
case ELookingUp:
iResolver.Close();
if (iStatus == KErrNone)
// DNS look up successful
{
iNameRecord = iNameEntry();
// Extract domain name and IP address from name record
iConsole->PrintNotify(KDomainName);
iConsole->PrintNotify(iNameRecord.iName);
TInetAddr::Cast(iNameRecord.iAddr).Output(ipAddr);
iConsole->PrintNotify(KIPAddress);
iConsole->PrintNotify(ipAddr);
// And connect to the IP address
ConnectL(TInetAddr::Cast(iNameRecord.iAddr).Address());
}
else
{
iStatus = ELookUpFailed;
iConsole->ErrorNotify(KDNSFailed, iStatus.Int());
}
break;
default:;
};
}
CEchoEngine::~CEchoEngine()
{
delete iEchoRead;
delete iEchoWrite;
delete iTimer;
iEchoSocket.Close();
iSocketServ.Close();
}
/*
Implements MTimeOutNotify: called when timeout expired
*/
void CEchoEngine::TimerExpired()
{
Cancel();
iEngineStatus = ETimedOut;
TRequestStatus* p=&iStatus;
SetActive();
User::RequestComplete(p, ETimedOut);
}
/*
Shutdown connection request
*/
EXPORT_C void CEchoEngine::Stop()
{
_LIT(KETerminate,"\n<CEchoEngine> Terminating\n");
iConsole->PrintNotify(KETerminate);
switch (iEngineStatus)
{
case EConnected:
// Stop live connection
iEchoRead->Cancel();
iEchoWrite->Cancel();
break;
case EConnecting:
case ELookingUp:
// if request to CEchoEngine, then stop it
Cancel();
break;
default:;
}
}
/*
CEchoRead: active object wrapping comms read requests
*/
CEchoRead::CEchoRead() : CActive(EPriorityStandard)
{
}
CEchoRead* CEchoRead::NewL(RSocket* aSocket, MUINotify* aConsole)
{
CEchoRead* self = NewLC(aSocket, aConsole);
CleanupStack::Pop();
return self;
}
CEchoRead* CEchoRead::NewLC(RSocket* aSocket, MUINotify* aConsole)
{
CEchoRead* self = new(ELeave) CEchoRead;
CleanupStack::PushL(self);
self->ConstructL(aSocket, aConsole);
return self;
}
void CEchoRead::ConstructL(RSocket* aSocket, MUINotify* aConsole)
{
iEchoSocket = aSocket;
iConsole = aConsole;
CActiveScheduler::Add(this);
}
/*
Cancel asychronous read request
*/
void CEchoRead::DoCancel()
{
iEchoSocket->CancelRead();
}
/*
Active object request complete handler
*/
void CEchoRead::RunL()
{
if (iStatus == KErrNone)
// Character has been read from socket
{
_LIT(KDot,".");
iConsole->PrintNotify(KDot);
TBuf16<1> Buffer;
Buffer.Copy(iBuffer);
iConsole->PrintNotify(Buffer);
IssueRead();
// TInetAddr &ipAddr = GetHostby;
// IssueRecvFrom(ipAddr);
}
else
{
// Error: pass it up to user interface
_LIT(KCEchoReadError,"\nCEchoRead error");
iConsole->ErrorNotify(KCEchoReadError, iStatus.Int());
}
}
/*
Read data from a stream socket
*/
void CEchoRead::IssueRead()
{
if (!IsActive())
{
iEchoSocket->Recv(iBuffer, 0, iStatus);
SetActive();
}
}
/*
This function is not actually used -
It shows how to read data from a datagram socket
*/
void CEchoRead::IssueRecvFrom(TInetAddr &aAddr)
{
iEchoSocket->RecvFrom(iBuffer,aAddr,NULL,iStatus);
SetActive();
};
/*
CEchoWrite: active object wrapping comms write requests
*/
CEchoWrite::CEchoWrite() : CActive(EPriorityStandard)
{
};
CEchoWrite* CEchoWrite::NewL(RSocket* aSocket, MUINotify* aConsole)
{
CEchoWrite* self = NewLC(aSocket, aConsole);
CleanupStack::Pop();
return self;
};
CEchoWrite* CEchoWrite::NewLC(RSocket* aSocket, MUINotify* aConsole)
{
CEchoWrite* self = new(ELeave) CEchoWrite;
CleanupStack::PushL(self);
self->ConstructL(aSocket, aConsole);
return self;
};
/*
ConstructL function - adds the active object to the Scheduler
*/
void CEchoWrite::ConstructL(RSocket* aSocket, MUINotify* aConsole)
{
iEchoSocket = aSocket;
iConsole = aConsole;
CActiveScheduler::Add(this);
iTimeOut = KTimeOut;
iTimer = CTimeOutTimer::NewL(10, *this);
iWriteStatus = EWaiting;
};
CEchoWrite::~CEchoWrite()
{
delete iTimer;
}
/*
Cancels asychronous write request
*/
void CEchoWrite::DoCancel()
{
iEchoSocket->CancelWrite();
};
/*
Implements MTimeOutNotify: called when timeout expired
*/
void CEchoWrite::TimerExpired()
{
Cancel();
iWriteStatus = ETimedOut;
TRequestStatus* p=&iStatus;
SetActive();
User::RequestComplete(p, ETimedOut);
}
/*
Active object request complete handler
*/
void CEchoWrite::RunL()
{
if (iStatus == KErrNone)
{
_LIT(KWriteOperationTimedOut,"\nWrite operation timed out");
switch(iWriteStatus)
{
// Character has been written to socket
case ESending:
// Cancel TimeOut timer
iTimer->Cancel();
iWriteStatus = EWaiting;
break;
// Request timed out
case ETimedOut:
iConsole->ErrorNotify(KWriteOperationTimedOut, KErrTimedOut);
break;
default:;
};
}
else
{
// Error: pass it up to user interface
_LIT(KCEchoWriteError,"\nCEchoWrite error");
iConsole->ErrorNotify(KCEchoWriteError, iStatus.Int());
}
}
/*
Write data to a stream socket
*/
void CEchoWrite::IssueWrite(const TChar &aChar)
{
// Set up buffer
iBuffer.SetLength(0);
iBuffer.Append(aChar);
iEchoSocket->Write(iBuffer, iStatus);
// Request timeout
iTimer->After(iTimeOut);
SetActive();
iWriteStatus = ESending;
};
void CEchoWrite::IssueSendTo(TInetAddr &aAddr, const TChar &aChar)
// This function is not actually used -
// it shows how to write data to a datagram socket
{
// Set up buffer
iBuffer.SetLength(0);
iBuffer.Append(aChar);
iEchoSocket->SendTo(iBuffer,aAddr,NULL,iStatus);
iTimer->After(iTimeOut);
SetActive();
iWriteStatus = ESending;
};
/*
CTimeOutTimer: timer for comms time-outs
*/
CTimeOutTimer::CTimeOutTimer(const TInt aPriority)
: CTimer(aPriority)
{
}
CTimeOutTimer::~CTimeOutTimer()
{
Cancel();
}
CTimeOutTimer* CTimeOutTimer::NewL(const TInt aPriority, MTimeOutNotify& aTimeOutNotify)
{
CTimeOutTimer *p = new (ELeave) CTimeOutTimer(aPriority);
CleanupStack::PushL(p);
p->ConstructL(aTimeOutNotify);
CleanupStack::Pop();
return p;
}
/**
* ConstructL function is used to add the active object to the scheduler
*/
void CTimeOutTimer::ConstructL(MTimeOutNotify &aTimeOutNotify)
{
iNotify=&aTimeOutNotify;
CTimer::ConstructL();
CActiveScheduler::Add(this);
}
/**
Timer request has completed, so notify the timer's owner
*/
void CTimeOutTimer::RunL()
{
iNotify->TimerExpired();
}
// ECHOENG.H
//
// Copyright (c) 1997-1999 Symbian Ltd. All rights reserved.
//
// Declares MTimeOutNotify, MUINotify, CEchoEngine
// CEchoRead, CEchoWrite, CTimeOutTimer
#ifndef _ECHOENG_H_
#define _ECHOENG_H_
#include <e32cons.h>
#include <in_sock.h>
#include <nifman.h>
// MTimeOutNotify: used in conjunction with CTimeOutTimer class
class MTimeOutNotify
{
public:
virtual void TimerExpired() = 0;
};
// MUINotify: implemented by user interfaces; engine up calls
class MUINotify
{
public:
virtual void PrintNotify(const TDesC& aMessage) = 0;
virtual void PrintNotify(TInt aMessage) = 0;
virtual void ErrorNotify(const TDesC& aErrMessage, TInt aErrCode) = 0;
};
// CTimeOutTimer: timer for comms time-outs
class CTimeOutTimer: public CTimer
{
public:
static CTimeOutTimer* NewL(const TInt aPriority, MTimeOutNotify& aTimeOutNotify);
~CTimeOutTimer();
protected:
CTimeOutTimer(const TInt aPriority);
void ConstructL(MTimeOutNotify& aTimeOutNotify);
virtual void RunL();
private:
MTimeOutNotify* iNotify;
};
// CEchoRead: active object wrapping comms read requests
class CEchoRead : public CActive
{
public:
static CEchoRead* NewL(RSocket* aSocket, MUINotify* aConsole);
static CEchoRead* NewLC(RSocket* aSocket, MUINotify* aConsole);
void ConstructL(RSocket* aSocket, MUINotify* aConsole);
void IssueRead();
void IssueRecvFrom(TInetAddr &aAddr);
//Implemented functions from CActive
void DoCancel();
void RunL();
protected:
CEchoRead();
private:
MUINotify* iConsole;
RSocket* iEchoSocket;
TBuf8<1> iBuffer;
};
// CEchoWrite: active object wrapping comms write requests
class CEchoWrite : public CActive, public MTimeOutNotify
{
public:
enum TWriteState
{
ESending, EWaiting ,ETimedOut
};
public:
static CEchoWrite* NewL(RSocket* aSocket, MUINotify* aConsole);
static CEchoWrite* NewLC(RSocket* aSocket, MUINotify* aConsole);
~CEchoWrite();
void ConstructL(RSocket* aSocket, MUINotify* aConsole);
void IssueWrite(const TChar &aChar);
void IssueSendTo(TInetAddr &aAddr, const TChar &aChar);
//Implemented functions from CActive
void DoCancel();
void RunL();
//Implemented functions from MNTimeOutNotify
void TimerExpired();
protected:
CEchoWrite();
private:
MUINotify* iConsole;
RSocket* iEchoSocket;
TBuf8<1> iBuffer;
CTimeOutTimer* iTimer;
TInt iTimeOut;
TWriteState iWriteStatus;
};
// CEchoEngine: main engine class for connection and shutdown
class CEchoEngine : public CActive, public MTimeOutNotify
{
public:
enum TEchoEngineState
{
EComplete, EConnecting, EConnected, ETimedOut,
ELookingUp, ELookUpFailed, EConnectFailed,
};
public:
IMPORT_C CEchoEngine();
IMPORT_C static CEchoEngine* NewL(MUINotify* aConsole);
IMPORT_C static CEchoEngine* NewLC(MUINotify* aConsole);
IMPORT_C void ConstructL(MUINotify* aConsole);
IMPORT_C void Stop();
IMPORT_C void ConnectL(TUint32 aAddr);
IMPORT_C void ConnectL(const TDesC& aServerName);
IMPORT_C void Write(TChar aChar);
IMPORT_C void Read();
IMPORT_C void TestGetByAddr(TUint32 aAddr);
//Implemented functions from MTimeOutNotify
void TimerExpired();
//Implemented functions from CActive
void DoCancel();
void RunL();
~CEchoEngine();
private:
TEchoEngineState iEngineStatus;
MUINotify* iConsole;
CEchoRead* iEchoRead;
CEchoWrite* iEchoWrite;
RSocket iEchoSocket;
RSocketServ iSocketServ;
RHostResolver iResolver;
TNameEntry iNameEntry;
TNameRecord iNameRecord;
CTimeOutTimer* iTimer;
TInt iTimeOut;
TInetAddr iAddress;
};
#endif
// Echoeng.mmp
//
// Copyright (c) 2000-2005 Symbian software Ltd. All rights reserved.
// using relative paths for sourcepath and user includes
// Exports are unfrozen
TARGET echoeng.dll
TARGETTYPE dll
UID 0x10004853
VENDORID 0x70000001
CAPABILITY All -TCB
SOURCEPATH .
SOURCE echoeng.cpp
USERINCLUDE .
SYSTEMINCLUDE \Epoc32\include
LIBRARY euser.lib insock.lib esock.lib
#if defined(WINS)
deffile .\echoengWINS.def
#else if defined(ARM)
deffile .\echoengARM.def
#endif
The TCP example is a client for the simple Echo protocol. A server implementing this protocol, defined in RFC862, simply listens on port 7 for incoming data, and returns it to the client. EchoClientEngine is a DLL that implements the engine component of the client. It contains active object classes that encapsulate reading, writing and connect operations. The related example project EchoClientUI provides a GUI interface to drive the engine.
RSocketServ
: socket server
RSocket: socket
RHostResolver
: host name resolver
TNameEntry
: name entry
TNameRecord
: name record
CTimer
: abstract timer