Symbian
Symbian OS Library

SYMBIAN OS V9.3

[Index] [Spacer] [Previous] [Next]



EchoClientEngine: TCP/IP echo client engine


Example code

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

[Top]


Description

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.

[Top]


Classes used