// UB_SVR.CPP
//
// Copyright (c) 1995-1999 Symbian Ltd.  All rights reserved.
//

#include "ub_std.h"
//#define __DEBUG_IMAGE__ 1
#if defined(__DEBUG_IMAGE__) && defined (__EPOC32__)
#include "e32svr.h" 
#define __IF_DEBUG(t) {RDebug debug;debug.t;}
#else
#define __IF_DEBUG(t)
#endif

class RMessageS : public RMessage
	{
public:
	inline CSession& Session() const;
	};

inline CSession& RMessageS::Session() const
	{return(*(CSession*)iSessionPtr);}

EXPORT_C CSession::CSession(RThread aClient)
//
// Constructor
//
	: iClient(aClient)
	{

//	iLink.iNext=NULL;
	__DECLARE_NAME(_S("CSession"));
	}

EXPORT_C CSession::~CSession()
//
// Destructor
//
	{

	if (iLink.iNext!=NULL)
		iLink.Deque();
	}

EXPORT_C void CSession::CreateL(const CServer& aServer)
//
// Default create implementation.
//
	{

	iServer=&aServer;
	}

EXPORT_C void CSession::ReadL(const TAny *aPtr,TDes8 &aDes) const
//
// Read 8 bit descriptor from the client at offset 0.
//
	{

	iClient.ReadL(aPtr,aDes,0);
	}

EXPORT_C void CSession::ReadL(const TAny *aPtr,TDes8 &aDes,TInt anOffset) const
//
// Read 8 bit descriptor from the client at anOffset.
//
	{

	iClient.ReadL(aPtr,aDes,anOffset);
	}

EXPORT_C void CSession::ReadL(const TAny *aPtr,TDes16 &aDes) const
//
// Read 16 bit descriptor from the client at offset 0.
//
	{

	iClient.ReadL(aPtr,aDes,0);
	}

EXPORT_C void CSession::ReadL(const TAny *aPtr,TDes16 &aDes,TInt anOffset) const
//
// Read 16 bit descriptor from the client at anOffset.
//
	{

	iClient.ReadL(aPtr,aDes,anOffset);
	}

EXPORT_C void CSession::WriteL(const TAny *aPtr,const TDesC8 &aDes) const
//
// Write 8 bit descriptor to the client at offset 0.
//
	{

	iClient.WriteL(aPtr,aDes,0);
	}

EXPORT_C void CSession::WriteL(const TAny *aPtr,const TDesC8 &aDes,TInt anOffset) const
//
// Write 8 bit descriptor to the client at anOffset.
//
	{

	iClient.WriteL(aPtr,aDes,anOffset);
	}

EXPORT_C void CSession::WriteL(const TAny *aPtr,const TDesC16 &aDes) const
//
// Write 16 bit descriptor to the client at offset 0.
//
	{

	iClient.WriteL(aPtr,aDes,0);
	}

EXPORT_C void CSession::WriteL(const TAny *aPtr,const TDesC16 &aDes,TInt anOffset) const
//
// Write 16 bit descriptor to the client at anOffset.
//
	{

	iClient.WriteL(aPtr,aDes,anOffset);
	}

EXPORT_C void CSession::Kill(TInt aReason) const
//
// Kill the client
//
	{

	((CSession *)this)->iClient.Kill(aReason);
	}

EXPORT_C void CSession::Terminate(TInt aReason) const
//
// Terminate the client
//
	{

	((CSession *)this)->iClient.Terminate(aReason);
	}

EXPORT_C void CSession::Panic(const TDesC &aCategory,TInt aReason) const
//
// Panic the client and free this message.
//
	{

	__IF_DEBUG(Print(_L("CSession::Panic %S %d"),&aCategory,aReason));
	((CSession *)this)->iClient.Panic(aCategory,aReason);
	}

EXPORT_C void CSession::ResourceCountMarkStart()
//
// Initialize the resource count. Panics if count < 0
//
	{
	
	iResourceCountMark=CountResources();
	if (iResourceCountMark==KErrGeneral)
		Panic(_L("CSession"),ESesCountResourcesNotImplemented);
	}

EXPORT_C void CSession::ResourceCountMarkEnd()
//
// Panic if resource count != iResourceCountMark
//
	{

	if (iResourceCountMark!=CountResources())
		Panic(_L("CSession"),ESesFoundResCountHeaven);
	}

EXPORT_C TInt CSession::CountResources()
//
// Default implementation returns KErrGeneral 
//
	{

	return KErrGeneral;
	}

EXPORT_C CServer::CServer(TInt aPriority)
//
// Constructor
//
	: CActive(aPriority),iSessionQ(_FOFF(CSession,iLink)),iSessionIter(iSessionQ)
	{

//	iName=NULL;
	iControl=EMultipleSessions;
	__DECLARE_NAME(_S("CServer"));
	}

EXPORT_C CServer::~CServer()
//
// Destructor
//
	{

	Cancel();
	while (!iSessionQ.IsEmpty())
		{
		CSession *pS=iSessionQ.First();
		pS->iLink.Deque();
		delete pS;
		}
	delete iName;
	iServer.Close();
	}

EXPORT_C TInt CServer::Start()
//
// Add to the request manager and request the first message.
//
	{

	__ASSERT_ALWAYS(iName!=NULL,Panic(ESvrNoServerName));
	TInt r=iServer.CreateGlobal(*iName);
	if (r==KErrNone)
		{
		CActiveScheduler::Add(this);
		iServer.Receive(iStatus);
		SetActive();
		}
	return(r);
	}

EXPORT_C void CServer::StartL()
//
// Add to the request manager and request the first message.
//
	{

	User::LeaveIfError(Start());
	}

EXPORT_C void CServer::DoCancel()
//
// Cancel the message receive.
//
	{

	iServer.Cancel();
	}

EXPORT_C TBool CServer::IsClientAlready(const RThread &aClient)
//
// Return ETrue if aClient is already a client.
//
	{

	TDblQueIter<CSession> q(iSessionQ);
	CSession *pS;
	while ((pS=q++)!=NULL)
		{
		if (pS->Client().Handle()==aClient.Handle())
			return(ETrue);
		}
	return(EFalse);
	}

EXPORT_C void CServer::CreateSessionL(RThread aClient,const TVersion &aVersion,CSession * &aSession) const
//
// Create a new session
//
	{

	aSession=NewSessionL(aClient,aVersion);
	aSession->CreateL(*this);
	}

#pragma warning( disable : 4702 )	// unreachable code
EXPORT_C void CServer::Connect()
//
// Handle a connect request. Ptr0()==DConnection,Ptr1()==Version.
//
	{

	const RMessage &m=iServer.Message();
	TPckgBuf<TVersion> v;
	m.ReadL(m.Ptr1(),v);
	if (iControl==ESingleSession && IsClientAlready(m.Client()))
		{
		m.Complete(KErrAlreadyExists);
		return;
		}
	CSession *pC=NULL;
	TRAPD(r,CreateSessionL(m.Client(),v(),pC))
	if (r==KErrNone)
		{
		iSessionQ.AddLast(*pC);
		iServer.SetSessionPtr(m,pC);
		}
	else
		delete pC;
	m.Complete(r);
	}
#pragma warning( default : 4702 )

#ifndef __CSERVER_MACHINE_CODED__
EXPORT_C void CServer::RunL()
//
// Handle message reception.
//
	{

	iMessage=iServer.Message();
	CSession& session=*((CSession*)iMessage.iSessionPtr);

	TInt f=iMessage.Function();
	switch (f)
		{
	case RMessage::EConnect:
		Connect();
		break;
	case RMessage::EDisConnect:
		delete &session;
		iMessage.Complete(KErrNone); // Jane
		break;
	default:
		if (f>=0)
			session.ServiceL(iMessage);
		else
			{
			RThread t=iMessage.Client(); // Needed as m.Client() returns const RThread
			t.Panic(Category(),ESvrBadMessageNumber);
			}
		}
	if (!IsActive()) // the ServiceL() may have started already
		ReStart();
	}
#else
GLDEF_C void PanicBadMessageNumber(TInt aThreadHandle)
	{
	RThread t;
	t.SetHandle(aThreadHandle);
	t.Panic(Category(),ESvrBadMessageNumber);
	}
#endif

EXPORT_C void CServer::ReStart()
//
// Restart the server
//
	{

	iServer.Receive(iStatus);
	SetActive();
	}