Symbian Developer Library

SYMBIAN OS V6.1 EDITION FOR C++

[Index] [Glossary] [Previous] [Next]



How to implement a simple server interface


Handling asynchronous requests

The implementation of a server requires a class derived from CServer. This is the active object base class responsible for handling the asynchronous requests from the client program.


Construction and initialisation

An instance of the CServer derived class is, typically, created by the server's thread function. As an active object, it needs a priority and this is passed as a parameter to the constructor. The choice of priority value depends on the server's design. If the server can have more than one active object, then it may be important for the CServer active object to have the highest priority.

The server can now be started.

void CCountServServer::New()
 {
 CCountServServer *pS=new CCountServServer(EPriority);
 __ASSERT_ALWAYS(pS!=NULL,PanicServer(ESvrCreateServer));
 TInt r=pS->Start(KCountServerName);
 __ASSERT_ALWAYS(r==KErrNone,PanicServer(ESvrStartServer));
 }

CServer::Start() adds the CServer active object to the active scheduler and issues the first request for messages. The server is now waiting for messages.

As with all active objects, the completion of requests for messages is handled by the CServer::RunL() protected member function.

Note that in ER5, the server name must be given its name as a step in the construction process. It is important this be done before starting the server otherwise an E32USER-CBase 55 panic is raised. The name is created in a heap descriptor and the pointer to this heap descriptor assigned to the public data member CServer::iName. The function New() in the above code fragment becomes:

void CCountServServer::New()
 {
 CCountServServer *pS=new CCountServServer(EPriority);
 __ASSERT_ALWAYS(pS!=NULL,PanicServer(ESvrCreateServer));
HBufC *pN=(&KCountServerName)->Alloc();
__ASSERT_ALWAYS(pN!=NULL,PanicServer(ESvrCreateServer));
pS->iName=pN;
 TInt r=pS->Start();
 __ASSERT_ALWAYS(r==KErrNone,PanicServer(ESvrStartServer));
 }


Handling requests

Requests for connection by a client thread result in the creation of a new session. A new CSharableSession object is constructed, initialised and added to the server’s session queue.

For a non sharable session, requests for disconnection by a client thread cause the relevant CSharableSession object to be deleted. The CSharableSession destructor should perform appropriate cleanup.

Any other message is passed to CSharableSession::ServiceL(). This function must be implemented by a derived class.

[Top]


Server side session representation

The base class CSharableSession represents a client's session on the server side. This class provides the standard session behaviour. The CSession class derived from CSharableSession adds the concept of the client thread. A class derived from CSession must be defined and implemented. The following class definition, taken from example code, is typical:

class CCountServSession : public CSession
 {
public:
 CCountServSession(RThread &aClient, CCountServServer * aServer);
 static CCountServSession* NewL(RThread &aClient, CCountServServer* aServer);
 virtual void ServiceL(const RMessage &aMessage);
 void DispatchMessageL(const RMessage &aMessage);
 void SetFromStringL();
 void Increase();
 void Decrease();
 void IncreaseBy();
 void DecreaseBy();
 void CounterValue();
 void Reset();
protected:
 void PanicClient(TInt aPanic) const;
 void Write(const TAny* aPtr,const TDesC8& aDes,TInt anOffset=0);
private:
 CCountServServer* iCountSvr;
 TInt iCount;
 };

Note the following:


ServiceL()

This is implemented as follows:

void CCountServSession::ServiceL(const RMessage& aMessage)
 {
 TRAPD(err,DispatchMessageL(aMessage));
 aMessage.Complete(err);
 }

Note


DispatchMessageL()

This is implemented as follows:

void CCountServSession::DispatchMessageL(const RMessage &aMessage)
 {
 switch (aMessage.Function())
        {
 case ECountServSetFromString:
  SetFromStringL();
  return;
 case ECountServIncrease:
  Increase();
  return;
 case ECountServIncreaseBy:
  IncreaseBy();
  return;
 case ECountServValue:
  CounterValue();
  return;
  ...............
  default:
  PanicClient(EBadRequest);
  return;
        }
 }


IncreaseBy()

This message service function is implemented as follows:

void CCountServSession::IncreaseBy()
 {
 iCount = iCount + Message().Int0();
 }

Note


SetFromStringL()

This message service function is implemented as follows:

void CCountServSession::SetFromStringL()
 {
 TInt res;
 const TAny* pD=Message().Ptr0();
 TInt desLen=Message().Client().GetDesLength(pD);
 HBufC8* writeBuf=HBufC8::New(desLen);
 TPtr initptr = writeBuf->Des();
 TRAP(res,Message().ReadL(pD,initptr));
 if (res!=KErrNone)
  PanicClient(EBadDescriptor);
 .......................
 // Do rest of work to convert from string to integer, and assign.
 }

Note


Write()

This is implemented as follows:

void CCountServSession::Write(const TAny* aPtr,const TDesC8& aDes,TInt anOffset)
 {
 TRAPD(ret,WriteL(aPtr,aDes,anOffset);)
 if (ret!=KErrNone)
  PanicClient(EBadDescriptor);
 }

Notes

void CCountServSession::CounterValue()
 {
 TPckgBuf<TInt> p(iCount);
 Write(Message().Ptr0(),p);
 }