How to implement a server interface with subsessions

Provides code snippets to help you to implement a server interface with subsessions.

A server side subsession is represented by an instance of a class derived from CObject.

The following sections refer to an example server, known as the count server. The code fragments are taken from the example that can be found at ...\examples\Base\IPC\ClientServer\complex.

In the example, a server side session is represented by the CSession2 derived class CCountSession. The server session can have any number of subsessions, referred to as counters in the example. The subsessions are instances of the CCountSubSession class and these are derived from CObject.

Unlike the implementation for a simple server interface, as shown in the example that can be found at ...\examples\Base\IPC\ClientServer\simple, the functions to service client requests, e.g. Increase(), are in class CCountSubSession rather than CCountSession.

The important points to note are:

  • the CCountSession class contains the object container for all the subsession objects which belong to this session.

  • the CCountServer class contains the one and only object container index through which all object containers within the server are produced.

  • the CCountSession class contains an object index through which a handle number can be generated for the subsession.

Server session representation

The CCountSession class is defined as:

class CCountSession : public CSession2
    {
public:
      // Create the session
    static CCountSession* NewL();
    
public:
      // Constructor
    CCountSession();
    
      // Called by client/server framework after 
      // session has been successfully created
    void CreateL(); 
        
      // Service request
    void ServiceL(const RMessage2& aMessage);
    void DispatchMessageL(const RMessage2& aMessage);

      // Creates new subsession
    void NewCounterL(const RMessage2& aMessage);  
      
      // Closes the session
    void CloseSession();
    
      // Gets the number of resources (i.e. CCountSubSession objects)
    void NumResources(const RMessage2& aMessage);
    
      // Utility to return the CCountSubSession (subsession) object
    CCountSubSession* CounterFromHandle(const RMessage2& aMessage,TInt aHandle);    

      // Delete the subsession object through its handle.
    void DeleteCounter(TInt aHandle);
      
      // Gets the number of server-side subsession objects.
    TInt CountResources();
      
      // Panics client
    void PanicClient(const RMessage2& aMessage,TInt aPanic) const;

private:
      // Object container for this session.
    CObjectCon *iContainer;

      // Object index which stores objects
      // (CCountSubSession instances) for this session.
    CObjectIx* iCountersObjectIndex;

      // Total number of resources. In this example
      // a resource is just the number of CCountSubSession objects.
    TInt iResourceCount;
    };

Notes

  • The data member iCountersObjectIndex is a pointer to an object index. Once a subsession object has been created and stored in its object container, it is then added to the object index to generate a unique handle number for the counter (subsession object).

  • The CCounterFromHandle() function returns the subsession object corresponding to a specified handle number.

  • The NewCounterL() function creates a new subsession object.

  • The DeleteCounter() function deletes a subsession object. This is called when the client program requests to close a subsession.

Subsession object representation

The CCountSubSession class which represents the subsession is defined as:

class CCountSubSession : public CObject
    {
public:
      // creates a new CCountSubSession object.
    static CCountSubSession* NewL(CCountSession* aSession);
    
public: 
    CCountSubSession(CCountSession* aSession);    
    void ConstructL(CCountSession* aSession);
    void SetFromStringL(const RMessage2& aMessage);
    void Increase();
    void IncreaseBy(const RMessage2& aMessage);
    void Decrease();
    void DecreaseBy(const RMessage2& aMessage);
    void Reset();
    void CounterValue(const RMessage2& aMessage);
   
protected:
      // The session that owns this CCountSubSession object.
    CCountSession* iSession;
    
private:
      // The counter value
    TInt iCount;
    };

Notes

  • The NewL() function creates and returns a new instance of the subsession object. This is called when the client requests the creation of a new subsession.

  • The message service functions Increase(), IncreaseBy() etc. respond appropriately to client requests.

Implementing a subsession request

Subsession requests are handled in a similar way to session requests.

A subsession request is initially handled by the associated session, i.e. it is passed to the appropriate CSession2::ServiceL().

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

The appropriate service function is called via DispatchMessageL() and the asynchronous request is completed with aMessage.Complete(). This applies to messages targeted at sessions and subsessions.

DispatchMessageL()

The following code fragment shows important parts of this function:

void CCountSession::DispatchMessageL(const RMessage2& aMessage)
    {
        // First check for session-relative requests
    switch (aMessage.Function())
        {
    case ECountServCreateSubSession:// Request to create a subsession
        NewCounterL(aMessage);
        return;
    case ECountServCloseSession:    // Request to delete a subsession
        CloseSession();
        return;
        ...
        }
    ...
 
                             // Must be a subsession request
                             // Find out Which subsession and
                             // forward the request to it.
    CCountSubSession* counter=CounterFromHandle(aMessage,aMessage.Int3())
    switch (aMessage.Function())
        {
        ...
    case ECountServValue:
        counter->CounterValue(aMessage);
        return;
    default:
        PanicClient(EBadRequest);
        return;
        }
    }
CCountSubSession* CCountSession::CounterFromHandle(const RMessage2& aMessage,TInt aHandle)
    {
    CCountSubSession* counter = (CCountSubSession*)iCountersObjectIndex->At(aHandle);
    if (counter == NULL)
        {
        PanicClient(aMessage, EBadSubsessionHandle); 
        }
    return counter;
    }

Notes

  • The function first checks for messages which are specific to a session and this includes those requests to create and delete a subsession.

  • After deciding that messages must be forwarded to a subsession, the function uses the handle number supplied through the fourth parameter in the message argument array and the CounterFromHandle() function to retrieve the appropriate subsession object.

  • It then invokes the appropriate message service function on that subsession to deal with the client request.

  • The At() function is provided by the CObject base class.