libraries/iosrv/server/server.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// server.cpp
// 
// Copyright (c) 2006 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
// 
// Initial Contributors:
// Accenture - Initial contribution
//

#include "server.h"
#include "pipe.h"
#include "console.h"
#include "file.h"
#include "null.h"
#include "persistentconsole.h"
#include "readwrite.h"
#include "clientserver.h"
#include "session.h"


#ifndef EKA2

//
// TServerStart.
//

TServerStart::TServerStart()
	{
	}

void TServerStart::SignalL()
	{
	RThread starter;
	User::LeaveIfError(starter.Open(iId));
	starter.RequestComplete(iStatus,KErrNone);
	starter.Close();
	}

#endif


//
// CShutdownTimer.
//

CShutdownTimer::CShutdownTimer()
	: CTimer(-1)
	{
	CActiveScheduler::Add(this);
	}

void CShutdownTimer::ConstructL()
	{
	CTimer::ConstructL();
	}

void CShutdownTimer::Start()
	{
	After(KShutdownDelay);
	}

void CShutdownTimer::RunL()
	{
	CActiveScheduler::Stop();
	}


//
// CIoServer.
//

CIoServer::CIoServer()
#ifdef EKA2
	: CServer2(0, ESharableSessions)
#else
	: CServer(0, ESharableSessions)
#endif
	{
	
	}

#ifdef EKA2
CServer2* CIoServer::NewLC()
#else
CServer* CIoServer::NewLC()
#endif
	{
	CIoServer* self=new(ELeave) CIoServer;
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CIoServer::~CIoServer()
	{
	if (iIoObjectContainerIndex)
		{
		iIoObjectContainerIndex->Remove(iIoObjectContainer);
		}
	delete iIoObjectContainerIndex;
#ifdef IOSRV_LOGGING
	delete iLog;
#endif
	}

void CIoServer::ConstructL()
	{
#if defined (__WINS__) && !defined (EKA2)
	RThread().SetPriority(EPriorityAbsoluteHigh);
#else
	RProcess().SetPriority(::EPriorityHigh);
#endif
	User::LeaveIfError(iFs.Connect());
#ifdef IOSRV_LOGGING
	iLog = CIoLog::NewL(iFs);
#endif
	iConfig.Init(); // Ignore error (defaults will be used).
	StartL(KIoServerName);
	iIoObjectContainerIndex = CObjectConIx::NewL();
	iIoObjectContainer = iIoObjectContainerIndex->CreateL();
	iShutdownTimer.ConstructL();
	iShutdownTimer.Start();
	}

#ifdef EKA2
	CSession2* CIoServer::NewSessionL(const TVersion&, const RMessage2&) const
#else
	CSharableSession* CIoServer::NewSessionL(const TVersion&) const
#endif
	{
	CIoSession* session = new(ELeave) CIoSession();
	LOG(CIoLog::Printf(_L("CIoSession 0x%08x created\r\n"), session));
	return session;
	}

void CIoServer::AddSession()
	{
	++iSessionCount;
	iShutdownTimer.Cancel();
	}

void CIoServer::DropSession()
	{
	if (--iSessionCount == 0)
		{
		iShutdownTimer.Start();
		}
	}

CIoPipe& CIoServer::CreatePipeLC()
	{
	CIoPipe* pipe = CIoPipe::NewLC();
	iIoObjectContainer->AddL(pipe);
	return *pipe;
	}

CIoConsole& CIoServer::CreateConsoleLC(const TDesC& aImplementation, const TDesC& aTitle, TSize aSize, MIoWriteEndPoint* aUnderlyingConsole, TUint aOptions)
	{
	CIoConsole* underlying = NULL;
	while (aUnderlyingConsole && aUnderlyingConsole->IoepIsType(RIoHandle::EPersistentConsole))
		{
		aUnderlyingConsole = ((CIoPersistentConsole*)aUnderlyingConsole)->TransientWriter();
		}
	if (aUnderlyingConsole && aUnderlyingConsole->IoepIsConsole())
		{
		underlying = (CIoConsole*)aUnderlyingConsole;
		}
		
	CIoConsole* console = CIoConsole::NewLC(aImplementation, aTitle, aSize, iConfig, underlying, aOptions);
	iIoObjectContainer->AddL(console);
	return *console;
	}

CIoFile& CIoServer::CreateFileLC(const TDesC& aName, RIoFile::TMode aMode)
	{
	CIoFile* file = CIoFile::NewLC(iFs, aName, aMode);
	iIoObjectContainer->AddL(file);
	return *file;
	}

CIoNull& CIoServer::CreateNullLC()
	{
	CIoNull* null = CIoNull::NewLC();
	iIoObjectContainer->AddL(null);
	return *null;
	}
	
CIoPersistentConsole& CIoServer::CreatePersistentConsoleLC(const TDesC& aName, const TDesC& aTitle, const RMsg& aMessage)
	{
	CIoPersistentConsole* pcons = CIoPersistentConsole::NewLC(aName, aTitle, *this, aMessage);
	iIoObjectContainer->AddL(pcons);
	return *pcons;
	}


CIoReadObject& CIoServer::CreateReadObjLC()
	{
	CIoReadObject* obj = CIoReadObject::NewLC(iNextReadObjId++);
	iIoObjectContainer->AddL(obj);
	return *obj;
	}

CIoWriteObject& CIoServer::CreateWriteObjLC()
	{
	CIoWriteObject* obj = CIoWriteObject::NewLC(iNextWriteObjId++);
	iIoObjectContainer->AddL(obj);
	return *obj;
	}

CIoReadObject* CIoServer::NextReadObj(TThreadId aOwningThread) const
	{
	return (CIoReadObject*)DoFindObj(RIoHandle::EReadObject, aOwningThread, ETrue);
	}

CIoReadWriteObject* CIoServer::DoFindObj(RIoHandle::TType aType, TThreadId aOwningThread, TBool aNext) const
	{
	CIoReadWriteObject* lastMatchingObj = NULL;
	const TInt numObjs = iIoObjectContainer->Count();
	for (TInt i = 0; i < numObjs; ++i)
		{
		CIoObject* obj = (CIoObject*)(*iIoObjectContainer)[i];
		if (obj->IsType(aType))
			{
			CIoReadWriteObject* readWriteObj = (CIoReadWriteObject*)obj;
			if (aNext && readWriteObj->IsOwner(aOwningThread) && !readWriteObj->OpenedByOwner())
				{
				// aNext==ETrue means we return the first matching object that isn't already opened by its owner
				return readWriteObj;
				}
			else if (!aNext && readWriteObj->IsOwner(aOwningThread) && readWriteObj->OpenedByOwner())
				{
				// aNext==EFalse means we return the last matching object that *is* opened
				lastMatchingObj = readWriteObj;
				}
			}
		}
	return lastMatchingObj;
	}

CIoWriteObject* CIoServer::NextWriteObj(TThreadId aOwningThread) const
	{
	return (CIoWriteObject*)DoFindObj(RIoHandle::EWriteObject, aOwningThread, ETrue);
	}

CIoReadObject* CIoServer::LastOpenedReadObj(TThreadId aOwningThread) const
	{
	return (CIoReadObject*)DoFindObj(RIoHandle::EReadObject, aOwningThread, EFalse);
	}

CIoWriteObject* CIoServer::LastOpenedWriteObj(TThreadId aOwningThread) const
	{
	return (CIoWriteObject*)DoFindObj(RIoHandle::EWriteObject, aOwningThread, EFalse);
	}

CIoPersistentConsole& CIoServer::FindPersistentConsoleL(const TDesC& aName)
	{
	const TInt numObjs = iIoObjectContainer->Count();
	for (TInt i=0; i<numObjs; ++i)
		{
		CIoObject* obj = (CIoObject*)(*iIoObjectContainer)[i];
		if (obj->IsType(RIoHandle::EPersistentConsole))
			{
			CIoPersistentConsole& pcons = (CIoPersistentConsole&)*obj;
			if (pcons.Name().Compare(aName)==0)
				{
				return pcons;
				}
			}
		}
	User::Leave(KErrNotFound);
	return *(CIoPersistentConsole*)1; // To keep the compiler happy.
	}

CIoObject* CIoServer::FindObjectByName(RIoHandle::TType aType, TInt& aFindHandle, const TDesC& aMatch, TName& aName) const
	{
	FOREVER
		{
		TInt err = iIoObjectContainer->FindByName(aFindHandle, aMatch, aName);
		if (err == KErrNone)
			{
			CIoObject* obj = (CIoObject*)iIoObjectContainer->At(aFindHandle);
			if (obj->IsType(aType))
				{
				return obj;
				}
			}
		else
			{
			break;
			}
		}
	return NULL;
	}

CIoObject& CIoServer::OpenObjectLC(TInt aFindHandle)
	{
	CIoObject* obj = (CIoObject*)iIoObjectContainer->At(aFindHandle);
	if (obj)
		{
		User::LeaveIfError(obj->Open());
		CleanupClosePushL(*obj);
		return *obj;
		}
	User::Leave(KErrNotFound);
	return *(CIoObject*)1; // To keep the compiler happy.
	}
	
const TIoConfig& CIoServer::Config()
	{
	return iConfig;
	}
	
void CIoServer::PersistentConsoleAddL(const TDesC16& aName, const CIoPersistentConsole& aCons)
	{
	if (iPersistentConsoleNames.Find(aName)!=NULL)
		{
		User::Leave(KErrAlreadyExists);
		}
	iPersistentConsoleNames.InsertL(&aName, &aCons);
	}
	
void CIoServer::PersistentConsoleRemove(const TDesC16& aName, const CIoPersistentConsole& aCons)
	{
	if (iPersistentConsoleNames.Find(aName) == &aCons)
		{
		iPersistentConsoleNames.Remove(&aName);
		}
	}

TInt CIoServer::RunError(TInt aError)
	{
	if (aError == KErrBadDescriptor)
		{
		PanicClient(Message(), EPanicBadDescriptor);
		}
	else if (aError == KErrBadHandle)
		{
		PanicClient(Message(), EPanicBadHandle);
		}
	else
		{
		LOG(CIoLog::LogCompletion(Message(), aError));
		Complete(Message(), aError);
		}

	ReStart();
	return KErrNone;
	}


//
// Statics.
//

void PanicClient(const RMsg& aMessage, TIoPanicReason aReason)
	{
	aMessage.Panic(KIoServerName, aReason);
	}

#ifdef EKA2
static void RunServerL()
#else
static void RunServerL(TServerStart& aStart)
#endif
	{
	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
	CleanupStack::PushL(scheduler);
	CActiveScheduler::Install(scheduler);

	CIoServer::NewLC();
#ifdef EKA2
	User::RenameThread(KIoServerName);
	RProcess::Rendezvous(KErrNone);
#else
	User::LeaveIfError(RThread().Rename(KIoServerName));
	aStart.SignalL();
#endif
	CActiveScheduler::Start();
	CleanupStack::PopAndDestroy(2, scheduler);
	}

#ifdef EKA2
static TInt RunServer()
#else
static TInt RunServer(TServerStart& aStart)
#endif
	{
	__UHEAP_MARK;
	CTrapCleanup* cleanup=CTrapCleanup::New();
	TInt r = KErrNoMemory;
	if (cleanup)
		{
#ifdef EKA2
		TRAP(r, RunServerL());
#else
		TRAP(r, RunServerL(aStart));
#endif
		delete cleanup;
		}
	__UHEAP_MARKEND;
	return r;
	}


#if defined(__WINS__) && !defined(EKA2)

static TInt ThreadFunction(TAny* aParms)
	{
	return RunServer(*static_cast<TServerStart*>(aParms));
	}

IMPORT_C TInt WinsMain();
EXPORT_C TInt WinsMain()
	{
	return reinterpret_cast<TInt>(&ThreadFunction);
	}

TInt E32Dll(TDllReason)
	{
	return KErrNone;
	}

#else
#ifdef EKA2

TInt E32Main()
	{
	return RunServer();
	}

#else

TInt TServerStart::GetCommand()
	{
	RProcess p;
	if (p.CommandLineLength() != (sizeof(TServerStart) / sizeof(TText)))
		{
		return KErrGeneral;
		}
	TPtr ptr(reinterpret_cast<TText*>(this), 0, (sizeof(TServerStart) / sizeof(TText)));
	p.CommandLine(ptr);
	return KErrNone;
	}

TInt E32Main()
	{
	TServerStart start;
	TInt r = start.GetCommand();
	if (r == KErrNone)
		{
		r = RunServer(start);
		}
	return r;
	}

#endif
#endif

#ifndef EKA2
const TAny* MessagePtr(const RMsg& aMessage, TInt aParam)
	{
	const TAny* ptr;
	switch (aParam)
		{
		case 0:
			{
			ptr = aMessage.Ptr0();
			break;
			}
		case 1:
			{
			ptr = aMessage.Ptr1();
			break;
			}
		case 2:
			{
			ptr = aMessage.Ptr2();
			break;
			}
		case 3:
			{
			ptr = aMessage.Ptr3();
			break;
			}
		default:
			{
			ASSERT(EFalse);
			ptr = NULL;
			}
		}
	return ptr;
	}
#endif
	
TInt DesLengthL(const RMsg& aMessage, TInt aParam)	
	{
#ifdef EKA2
	return aMessage.GetDesLengthL(aParam);
#else
	return aMessage.Client().GetDesLength(MessagePtr(aMessage, aParam));
#endif
	}
	
TInt MaxDesLengthL(const RMsg& aMessage, TInt aParam)
	{
#ifdef EKA2
	return aMessage.GetDesMaxLengthL(aParam);
#else
	return aMessage.Client().GetDesMaxLength(MessagePtr(aMessage, aParam));
#endif
	}

void MessageReadL(const RMsg& aMessage, TInt aParam, TDes8& aDes)
	{
#ifdef EKA2
	aMessage.ReadL(aParam, aDes);
#else
	aMessage.ReadL(MessagePtr(aMessage, aParam), aDes);
#endif
	}

void MessageReadL(const RMsg& aMessage, TInt aParam, TDes8& aDes, TInt aOffset)
	{
#ifdef EKA2
	aMessage.ReadL(aParam, aDes, aOffset);
#else
	aMessage.ReadL(MessagePtr(aMessage, aParam), aDes, aOffset);
#endif
	}

void MessageReadL(const RMsg& aMessage, TInt aParam, TDes16& aDes)
	{
#ifdef EKA2
	aMessage.ReadL(aParam, aDes);
#else
	aMessage.ReadL(MessagePtr(aMessage, aParam), aDes);
#endif
	}

void MessageReadL(const RMsg& aMessage, TInt aParam, TDes16& aDes, TInt aOffset)
	{
#ifdef EKA2
	aMessage.ReadL(aParam, aDes, aOffset);
#else
	aMessage.ReadL(MessagePtr(aMessage, aParam), aDes, aOffset);
#endif
	}

void MessageWriteL(const RMsg& aMessage, TInt aParam, const TDesC8& aDes)
	{
#ifdef EKA2
	aMessage.WriteL(aParam, aDes);
#else
	aMessage.WriteL(MessagePtr(aMessage, aParam), aDes);
#endif
	}

void MessageWriteL(const RMsg& aMessage, TInt aParam, const TDesC16& aDes)
	{
#ifdef EKA2
	aMessage.WriteL(aParam, aDes);
#else
	aMessage.WriteL(MessagePtr(aMessage, aParam), aDes);
#endif
	}
	
TInt MessageWrite(const RMsg& aMessage, TInt aParam, const TDesC8& aDes)
	{
#ifdef EKA2
	return aMessage.Write(aParam, aDes);
#else
	return aMessage.Write(MessagePtr(aMessage, aParam), aDes);
#endif
	}

TInt MessageWrite(const RMsg& aMessage, TInt aParam, const TDesC16& aDes)
	{
#ifdef EKA2
	return aMessage.Write(aParam, aDes);
#else
	return aMessage.Write(MessagePtr(aMessage, aParam), aDes);
#endif
	}

TBool MessagePending(const RMsg& aMessage)
	{
#ifdef EKA2
	return !aMessage.IsNull();
#else
	return aMessage != RMessagePtr();
#endif
	}

TThreadId ClientThreadIdL(const RMsg& aMessage)
	{
	TThreadId clientThreadId;
#ifdef EKA2
	RThread clientThread;
	aMessage.ClientL(clientThread);
	clientThreadId = clientThread.Id();
	clientThread.Close();
#else
	clientThreadId = aMessage.Client().Id();
#endif
	return clientThreadId;
	}

TFullName ClientNameL(const RMsg& aMessage)
	{
#ifdef EKA2
	RThread clientThread;
	aMessage.ClientL(clientThread);
	TFullName clientName(clientThread.FullName());
	clientThread.Close();
	return clientName;
#else
	return aMessage.Client().FullName();
#endif
	}

void Complete(const RMsg& aMessage, TInt aError)
	{
	LOG(CIoLog::LogCompletion(aMessage, aError));
	aMessage.Complete(aError);
	}

void CompleteIfPending(const RMsg& aMessage, TInt aError)
	{
	if (MessagePending(aMessage))
		{
		Complete(aMessage, aError);
		}
	}