First submission to Symbian Foundation staging server.
// 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);
}
}