Tuesday, September 8, 2009

Server crash notification in Symbian

It is possible to get a notification when a server has crashed.
For example,
If you have process A which is a client of server B. Now if process B crashes, the session started by process A becomes invalid. You can check the return value of request made to server B and then you can decide to restart the server B.
Alternatively you can logon to server B. So when server B dies, it sends a notification when it panics or is terminated. You can you check the documentation for more details ( check either for RUndertaker ,RThread or Rprocess)
Below is an example implementation.
----------------------------------------------------------
This is the interface class that has the virtual method ProcessTerminatedL() to indicate the termination of server.

#ifndef MSERVERMONITOR_H_
#define MSERVERMONITOR_H_
#include <e32const.h>
class MServerMonitor
{
public:
virtual ~MServerMonitor() {}
public: // Interface
/**
* Callback indicating the termination the Process.
*
*/
virtual void ProcessTerminatedL(TExitType aExitType) = 0;

};
#endif /* MPBK2SERVERMONITOR_H_ */

-------------------- cmyservermonitor.h --------------------------------------
This is the actual server monitor class. It is a simple class with an instance of RUndertaker object, that does the monitoring.

#ifndef C_MYSERVER_MONITOR_H_
#define C_MYSERVER_MONITOR_H_
#include <e32std.h>
#include <e32base.h>


class CMyServerMonitor:public CActive

{
public:
static CMyServerMonitor* NewLC(MServerMonitor& aReporter);
static CMyServerMonitor* NewL(MServerMonitor& aReporter);
~CMyServerMonitor();
public://from CActive
void RunL();
void DoCancel();
TInt RunError(TInt aError);
public:
TBool Monitoring();
void StartMonitoringL(TInt aThreadNumber);
void StopMonitoringL();

private:
CMyServerMonitor(MServerMonitor& aReporter);
void ConstructL();

private:
RUndertaker iUnderTaker ;
TInt iThreadNumber ;
MServerMonitor& iReporter;

};

#endif /*C_MYSERVER_MONITOR_H_*/
---------------------cmyservermonitor.cpp-------------------------------------
The implementation for the server monitor class.


#include "cmyservermonitor.h"

CMyServerMonitor::CMyServerMonitor(MServerMonitor& aReporter)
: CActive(EPriorityStandard),iReporter(aReporter), iThreadNumber(0)
{
CActiveScheduler::Add(this);
}


CMyServerMonitor::~CMyServerMonitor()
{
Cancel();
iUnderTaker.Close();
}

CMyServerMonitor* CMyServerMonitor::NewLC(MServerMonitor& aReporter)
{
CMyServerMonitor* self = new (ELeave)CMyServerMonitor(aReporter);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}

CMyServerMonitor* CMyServerMonitor::NewL(MServerMonitor& aReporter)
{
CMyServerMonitor* self=CMyServerMonitor::NewLC(aReporter);
CleanupStack::Pop(); // self;
return self;
}

void CMyServerMonitor::ConstructL()
{
iUnderTaker.Create();
}

void CMyServerMonitor::RunL()
{
if(iStatus == KErrDied)
{
//report reason
RThread th;
th.SetHandle(iThreadNumber);
TFullName name = th.FullName();
TExitType type = th.ExitType();
iReporter.ProcessTerminatedL(type);
th.Close();
}
else
{
//
//
}
}

void CMyServerMonitor::DoCancel()
{
iUnderTaker.LogonCancel();
}


TInt CMyServerMonitor::RunError(TInt aError)
{
return KErrNone;
}


void CMyServerMonitor::StartMonitoringL(TInt aThreadNumber)
{
iThreadNumber = aThreadNumber;
iUnderTaker.Logon(iStatus,iThreadNumber);
SetActive();
}

void CMyServerMonitor::StopMonitoringL()
{
Cancel();

}

TBool CMyServerMonitor::Monitoring()
{
return IsActive();
}
------------------------------------------------------------------

The Process (for example, class X) which wants to monitor should inherit from MServerMonitor and it should implment the ProcessTerminatedL(TExitType aExitType) method. Also class X, should create instance of CMyServerMonitor and start the monitoring by calling the StartMonitoringL(TInt aThreadNumber) method.

Below is sample code for the same

void X::ConstructL()
{
iServerMonitor = CMyServerMonitor::NewLC(*this);
CleanupStack::Pop();
StartServerMonitoringL();
}

void X::StartServerMonitoringL()
{

_LIT(KMatchName,"MyServer.exe*");
TFindThread procName(KMatchName);
TFullName processName;
RThread PsprocHandle;
TInt threadId = KErrNotFound;
if ( procName.Next(processName) == KErrNone )
{
TInt rc = PsprocHandle.Open(procName);
if (rc == KErrNone)
{
threadId = PsprocHandle.Id();
}
}
if(threadId != KErrNotFound)
{
//Start the logging process
iServerMonitor->StartMonitoringL(threadId);
}
}

void X::ProcessTerminatedL(TExitType aExitType)
{
if(aExitType == EExitPanic)
{
//Thread paniced. Restart the server
// Add code to restart the server here
// --
// --
// --

//Start the monitoring again
StartServerMonitoringL();
}
else //Exit other than panic
{

// take necessary action
}

}
----------------------------------------------------------


I hope the above code helps. Do add your comments if you find this post useful.

No comments: