Symbian
Symbian Developer Library

SYMBIAN OS V9.4

Feedback

[Index] [Previous] [Next]


server.cpp

// server.cpp
//
// Copyright (c) 2000 - 2006 Symbian Software Ltd.  All rights reserved.
//

// Transient server example - server implementation

#include "server.h"

inline CShutdown::CShutdown()
    :CTimer(-1)
    {CActiveScheduler::Add(this);}
inline void CShutdown::ConstructL()
    {CTimer::ConstructL();}
inline void CShutdown::Start()
    {After(KMyShutdownDelay);}

inline CMyServer::CMyServer()
    :CServer2(0,ESharableSessions)
    {}

inline CMySession::CMySession()
    {}
inline CMyServer& CMySession::Server()
    {return *static_cast<CMyServer*>(const_cast<CServer2*>(CSession2::Server()));}
inline TBool CMySession::ReceivePending() const
    {return !iReceiveMsg.IsNull();}


///////////////////////

void CMySession::CreateL()
//
// 2nd phase construct for sessions - called by the CServer framework
//
    {
    Server().AddSession();
    }

CMySession::~CMySession()
    {
    Server().DropSession();
    }

void CMySession::Send(const TDesC& aMessage)
//
// Deliver the message to the client, truncating if required
// If the write fails, panic the client, not the sender
//
    {
    if (ReceivePending())
        {
        TPtrC m(aMessage);
        if (iReceiveLen<aMessage.Length())
            m.Set(m.Left(iReceiveLen));
        TInt r=iReceiveMsg.Write(0,m);
        if (r==KErrNone)
            iReceiveMsg.Complete(KErrNone);
        else
            PanicClient(iReceiveMsg,EPanicBadDescriptor);
        }
    }

void CMySession::ServiceL(const RMessage2& aMessage)
//
// Handle a client request.
// Leaving is handled by CMyServer::ServiceError() which reports
// the error code to the client
//
    {
    switch (aMessage.Function())
        {
    case ESend:
        {
        TBuf<KMaxMyMessage> message;
        aMessage.ReadL(0,message);
        Server().Send(message);
        aMessage.Complete(KErrNone);
        break;
        }
    case EReceive:
        if (ReceivePending())
            PanicClient(aMessage,EPanicAlreadyReceiving);
        else
            {
            iReceiveMsg=aMessage;
            iReceiveLen=aMessage.Int1();
            }
        break;
    case ECancelReceive:
        if (ReceivePending())
            iReceiveMsg.Complete(KErrCancel);
        aMessage.Complete(KErrNone);
        break;
    default:
        PanicClient(aMessage,EPanicIllegalFunction);
        break;
        }
    }

void CMySession::ServiceError(const RMessage2& aMessage,TInt aError)
//
// Handle an error from CMySession::ServiceL()
// A bad descriptor error implies a badly programmed client, so panic it;
// otherwise use the default handling (report the error to the client)
//
    {
    if (aError==KErrBadDescriptor)
        PanicClient(aMessage,EPanicBadDescriptor);
    CSession2::ServiceError(aMessage,aError);
    }

void CShutdown::RunL()
//
// Initiate server exit when the timer expires
//
    {
    CActiveScheduler::Stop();
    }

CServer2* CMyServer::NewLC()
    {
    CMyServer* self=new(ELeave) CMyServer;
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

void CMyServer::ConstructL()
//
// 2nd phase construction - ensure the timer and server objects are running
//
    {
    StartL(KMyServerName);
    iShutdown.ConstructL();
    // ensure that the server still exits even if the 1st client fails to connect
    iShutdown.Start();
    }


CSession2* CMyServer::NewSessionL(const TVersion&,const RMessage2&) const
//
// Cretae a new client session. This should really check the version number.
//
    {
    return new(ELeave) CMySession();
    }

void CMyServer::AddSession()
//
// A new session is being created
// Cancel the shutdown timer if it was running
//
    {
    ++iSessionCount;
    iShutdown.Cancel();
    }

void CMyServer::DropSession()
//
// A session is being destroyed
// Start the shutdown timer if it is the last session.
//
    {
    if (--iSessionCount==0)
        iShutdown.Start();
    }

void CMyServer::Send(const TDesC& aMessage)
//
// Pass on the signal to all clients
//
    {
    iSessionIter.SetToFirst();
    CSession2* s;
    while ((s=iSessionIter++)!=0)
        static_cast<CMySession*>(s)->Send(aMessage);
    }

void PanicClient(const RMessagePtr2& aMessage,TMyPanic aPanic)
//
// RMessage::Panic() also completes the message. This is:
// (a) important for efficient cleanup within the kernel
// (b) a problem if the message is completed a second time
//
    {
    _LIT(KPanic,"MyServer");
    aMessage.Panic(KPanic,aPanic);
    }

static void RunServerL()
//
// Perform all server initialisation, in particular creation of the
// scheduler and server and then run the scheduler
//
    {
    // naming the server thread after the server helps to debug panics
    User::LeaveIfError(RThread::RenameMe(KMyServerName));
    //
    // create and install the active scheduler we need
    CActiveScheduler* s=new(ELeave) CActiveScheduler;
    CleanupStack::PushL(s);
    CActiveScheduler::Install(s);
    //
    // create the server (leave it on the cleanup stack)
    CMyServer::NewLC();
    //
    // Initialisation complete, now signal the client
    RProcess::Rendezvous(KErrNone);
    //
    // Ready to run
    CActiveScheduler::Start();
    //
    // Cleanup the server and scheduler
    CleanupStack::PopAndDestroy(2);
    }

TInt E32Main()
//
// Server process entry-point
//
    {
    __UHEAP_MARK;
    //
    CTrapCleanup* cleanup=CTrapCleanup::New();
    TInt r=KErrNoMemory;
    if (cleanup)
        {
        TRAP(r,RunServerL());
        delete cleanup;
        }
    //
    __UHEAP_MARKEND;
    return r;
    }