plugins/consoles/consoleproxy/src/server.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 37 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// server.cpp
// 
// Copyright (c) 2009 - 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 <consoleproxy.h>
#include "server.h"

_LIT(KPronxyConsolePanic, "proxyconsole");
	
void Panic(TConsoleProxyPanic aReason)
	{
	User::Panic(KPronxyConsolePanic, aReason);
	}


void ServerThreadL(TServerParams* aParams)
	{
	CActiveScheduler* as = new(ELeave)CActiveScheduler;
	CleanupStack::PushL(as);
	CActiveScheduler::Install(as);
	
	CConsoleProxyServer* server = (aParams->iServerNewL)(aParams->iServerParams);
	CleanupStack::PushL(server);
	
	aParams->iServer = server->Server();
	RThread::Rendezvous(KErrNone);
	
	CActiveScheduler::Start();
	
	CleanupStack::PopAndDestroy(2, as);
	}
		

TInt ServerThreadFunction(TAny* aArgs)
	{
	__UHEAP_MARK;
	User::SetCritical(User::ENotCritical);
	
	TServerParams* params = (TServerParams*)aArgs;
	
	CTrapCleanup* cleanup = CTrapCleanup::New();
	if (!cleanup)
		{
		return KErrNoMemory;
		}
		
	TRAPD(err, ServerThreadL(params));
		
	delete cleanup;
	__UHEAP_MARKEND;
	return err;
	}
		
//______________________________________________________________________________
//						CConsoleProxyServer
CConsoleProxyServer* CConsoleProxyServer::NewL(TAny* aParams)
	{
	TConsoleProxyServerNewLParams* params = (TConsoleProxyServerNewLParams*)aParams;
	return NewL(params->iName, params->iAoPriority, params->iConsoleCreate);
	}
	
EXPORT_C CConsoleProxyServer* CConsoleProxyServer::NewL(const TDesC& aName, TInt aAoPriority, TConsoleCreateFunction aConsoleCreate)
	{
	CConsoleProxyServer* self = new(ELeave)CConsoleProxyServer(aConsoleCreate, aAoPriority);
	CleanupStack::PushL(self);
	self->ConstructL(aName);
	CleanupStack::Pop(self);
	return self;
	}
	
EXPORT_C void CConsoleProxyServer::ConstructL(const TDesC& aName)
	{
	StartL(aName);
	iShutdownTimer = CShutdownTimer::NewL(*this);
	iShutdownTimer->Start();
	}

EXPORT_C CConsoleProxyServer::CConsoleProxyServer(TConsoleCreateFunction aConsoleCreate, TInt aAoPriority)
	: CServer2(aAoPriority, CServer2::ESharableSessions)
	, iConsoleCreate(aConsoleCreate)
	{
	}

EXPORT_C CConsoleProxyServer::~CConsoleProxyServer()
	{
	delete iShutdownTimer;
	iShutdownTimer = NULL; // Can be referenced by session destructors which run after this, as part of ~CServer2, which will call ~CConsoleProxySession which can call DropSession...
	}
	
EXPORT_C void CConsoleProxyServer::ShutdownTimerExpired()
	{
	CActiveScheduler::Stop();
	}

EXPORT_C CSession2* CConsoleProxyServer::NewSessionL(const TVersion&,const RMessage2&) const
	{
	return new(ELeave)CConsoleProxySession(iConsoleCreate);
	}

void CConsoleProxyServer::AddSession()
	{
	iShutdownTimer->Cancel();
	++iSessionCount;
	}

void CConsoleProxyServer::DropSession()
	{
	--iSessionCount;
	if ((iSessionCount==0) && iShutdownTimer && (!iShutdownTimer->IsActive()))
		{
		iShutdownTimer->Start();
		}
	}

//______________________________________________________________________________
//						CConsoleProxySession
EXPORT_C CConsoleProxySession::CConsoleProxySession(TConsoleCreateFunction aConsoleCreate)
	: iConsoleCreate(aConsoleCreate)
	{
	}
	
EXPORT_C CConsoleProxySession::CConsoleProxySession(MProxiedConsole* aConsole)
	: iConsole(aConsole)
	{
	iConsole->Open();
	}

EXPORT_C CConsoleProxySession::~CConsoleProxySession()
	{
	Server()->DropSession();
	if (!iReadMessage.IsNull())
		{
		iReadMessage.Complete(KErrDisconnected);
		if (iConsole) iConsole->ReadCancel();
		}
	if (iConsole) iConsole->Close();
	}

EXPORT_C void CConsoleProxySession::CreateL()
	{
	Server()->AddSession();
	}

EXPORT_C void CConsoleProxySession::ServiceL(const RMessage2& aMessage)
	{
	if (!iConsole && (aMessage.Function() != RConsoleProxy::ECreate))
		{
		User::Leave(KErrNotReady);
		}
	RBuf buf;
	CleanupClosePushL(buf);
	TBool complete = ETrue;
	switch (aMessage.Function())
		{
	case RConsoleProxy::ECreate:
		CreateL(aMessage);
		break;
	case RConsoleProxy::ERead:
		if (!iReadMessage.IsNull()) User::Leave(KErrAlreadyExists);
		iReadType = EReadBasic;
		iReadMessage = aMessage;
		iConsole->Read(*this);
		complete = EFalse;
		break;
	case RConsoleProxy::EReadKey:
		if (!iReadMessage.IsNull()) User::Leave(KErrAlreadyExists);
		iReadType = EReadKeys;
		iReadMessage = aMessage;
		iConsole->Read(*this);
		complete = EFalse;
		break;
	case RConsoleProxy::EReadCancel:
		if (!iReadMessage.IsNull())
			{
			iReadMessage.Complete(KErrCancel);
			iConsole->ReadCancel();
			}
		break;
	case RConsoleProxy::EWrite:
		buf.CreateL(aMessage.GetDesLengthL(0));
		aMessage.ReadL(0, buf);
		iConsole->Console()->Write(buf);
		break;
	case RConsoleProxy::EGetCursorPos:
		{
		TPckgBuf<TPoint> pos;
		pos() = iConsole->Console()->CursorPos();
		aMessage.WriteL(0, pos);
		break;
		}
	case RConsoleProxy::ESetCursorPosAbs:
		{
		TPoint pos(aMessage.Int0(), aMessage.Int1());
		iConsole->Console()->SetCursorPosAbs(pos);
		break;
		}
	case RConsoleProxy::ESetCursorPosRel:
		{
		TPoint pos(aMessage.Int0(), aMessage.Int1());
		iConsole->Console()->SetCursorPosRel(pos);
		break;
		}
	case RConsoleProxy::ESetCursorHeight:
		iConsole->Console()->SetCursorHeight(aMessage.Int0());
		break;
	case RConsoleProxy::ESetTitle:
		buf.CreateL(aMessage.GetDesLengthL(0));
		aMessage.ReadL(0, buf);
		iConsole->Console()->SetTitle(buf);
		break;
	case RConsoleProxy::EClearScreen:
		iConsole->Console()->ClearScreen();
		break;
	case RConsoleProxy::EClearToEndOfLine:
		iConsole->Console()->ClearToEndOfLine();
		break;
	case RConsoleProxy::EGetScreenSize:
		{
		TPckgBuf<TSize> size;
		if (aMessage.GetDesLengthL(0)!=size.Length()) User::Leave(KErrArgument);
		size() = iConsole->Console()->ScreenSize();
		aMessage.WriteL(0, size);
		break;
		}
	case RConsoleProxy::EGetKeyCode:
		{
		TPckg<TKeyCode> kc(iKeyCode);
		if (aMessage.GetDesLengthL(0)!=kc.Length()) User::Leave(KErrArgument);
		aMessage.WriteL(0, kc);
		break;
		}
	case RConsoleProxy::EGetKeyModifiers:
		{
		TPckg<TUint> mod(iKeyModifiers);
		if (aMessage.GetDesLengthL(0)!=mod.Length()) User::Leave(KErrArgument);
		aMessage.WriteL(0, mod);
		break;
		}
	case RConsoleProxy::ESetAttributes:
		{
		if (!iConsole) User::Leave(KErrNotReady);
		ConsoleAttributes::TAttributes attributes((TUint)aMessage.Int0(), (ConsoleAttributes::TColor)aMessage.Int1(), (ConsoleAttributes::TColor)aMessage.Int2());
		TInt err = ConsoleAttributes::Set(iConsole->Console(), attributes);
		aMessage.Complete(err);
		complete = EFalse;
		break;
		}
	case RConsoleProxy::EIsConstructed:
		{
		if (aMessage.GetDesLengthL(0)!=sizeof(TBool)) User::Leave(KErrArgument);
		if (!iConsole) User::Leave(KErrNotReady);
		if (!LazyConsole::IsLazy(iConsole->Console())) User::Leave(KErrExtensionNotSupported);
		TPckgBuf<TBool> constructed = LazyConsole::IsConstructed(iConsole->Console());
		aMessage.WriteL(0, constructed);
		complete = ETrue;
		break;
		}
	default:
		aMessage.Complete(KErrNotSupported);
		}
	CleanupStack::PopAndDestroy(&buf);
	if (complete)
		{
		aMessage.Complete(KErrNone);
		}
	}
	
EXPORT_C void CConsoleProxySession::ReadComplete(TInt aStatus)
	{
	iKeyCode = iConsole->Console()->KeyCode();
	iKeyModifiers = iConsole->Console()->KeyModifiers();
	if (!iReadMessage.IsNull())
		{
		TInt err = aStatus;
		if (iReadType == EReadKeys)
			{
			if (err == KErrNone)
				{
				err = iReadMessage.Write(0, TPckg<TKeyCode>(iKeyCode));
				}
			if (err == KErrNone)
				{
				err = iReadMessage.Write(1, TPckg<TUint>(iKeyModifiers));
				}	
			}
		
		iReadMessage.Complete(err);
		}
	}
	
EXPORT_C void CConsoleProxySession::DoCreateL(const TDesC& aTitle, const TSize& aSize)
	{
	__ASSERT_ALWAYS(!iConsole, Panic(EConsoleAlreadyCreated));
	MProxiedConsole* cons = InstantiateConsoleL();
	__ASSERT_ALWAYS(cons, Panic(ENoConsoleInstatiated));
	CleanupClosePushL(*cons);
	TName procName = RProcess().Name(); // econseik sets the process name to the console title...
	TInt err = cons->Console()->Create(aTitle, aSize);
	User::RenameProcess(procName.Left(procName.Locate('['))); // ...so restore it just in case
	User::LeaveIfError(err);
	
	ConsoleCreatedL(cons);
	
	iConsole = cons;
	CleanupStack::Pop(cons);
	}
	
EXPORT_C void CConsoleProxySession::ConsoleCreatedL(MProxiedConsole*)
	{
	}

void CConsoleProxySession::CreateL(const RMessage2& aMessage)
	{
	if (iConsole) User::Leave(KErrAlreadyExists);
	RBuf title;
	title.CreateL(aMessage.GetDesLengthL(0));
	CleanupClosePushL(title);
	aMessage.ReadL(0, title);
	
	TSize size(aMessage.Int1(), aMessage.Int2());
	
	DoCreateL(title, size);
	
	CleanupStack::PopAndDestroy(&title);
	}

EXPORT_C MProxiedConsole* CConsoleProxySession::InstantiateConsoleL()
	{
	return CConsoleWrapper::NewL(iConsoleCreate);
	}


//______________________________________________________________________________
//						MProxiedConsole
EXPORT_C MProxiedConsole* MProxiedConsole::DefaultL(CConsoleBase* aConsole)
	{
	return CConsoleWrapper::NewL(aConsole);
	}
//______________________________________________________________________________
//						CConsoleWrapper
CConsoleWrapper* CConsoleWrapper::NewL(TConsoleCreateFunction aConsoleCreate)
	{
	CConsoleWrapper* self = new(ELeave)CConsoleWrapper;
	CleanupStack::PushL(self);
	self->ConstructL(aConsoleCreate);
	CleanupStack::Pop(self);
	return self;
	}
	
CConsoleWrapper* CConsoleWrapper::NewL(CConsoleBase* aConsole)
	{
	CConsoleWrapper* self = new(ELeave)CConsoleWrapper;
	self->iConsole = aConsole;
	return self;	
	}
	
CConsoleWrapper::~CConsoleWrapper()
	{
	Cancel();
	delete iConsole;
	}

void CConsoleWrapper::Open()
	{
	++iRefCount;
	}

void CConsoleWrapper::Close()
	{
	--iRefCount;
	if (!iRefCount)
		{
		delete this;
		}
	}

CConsoleBase* CConsoleWrapper::Console()
	{
	return iConsole;
	}

void CConsoleWrapper::Read(CConsoleProxySession& aSession)
	{
	if (!IsActive())
		{
		iReader = &aSession;
		iConsole->Read(iStatus);
		SetActive();
		}
	}

void CConsoleWrapper::ReadCancel()
	{
	Cancel();
	iReader = NULL;
	}

void CConsoleWrapper::RunL()
	{
	iReader->ReadComplete(iStatus.Int());
	}

void CConsoleWrapper::DoCancel()
	{
	iConsole->ReadCancel();
	}

void CConsoleWrapper::ConstructL(TConsoleCreateFunction aConsoleCreate)
	{
	iConsole = aConsoleCreate();
	User::LeaveIfNull(iConsole);
	}

CConsoleWrapper::CConsoleWrapper()
	: CActive(CActive::EPriorityStandard)
	, iRefCount(1)
	{
	CActiveScheduler::Add(this);
	}


//______________________________________________________________________________
//						CShutdownTimer
CShutdownTimer* CShutdownTimer::NewL(CConsoleProxyServer& aServer)
	{
	CShutdownTimer* self = new(ELeave)CShutdownTimer(aServer);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}
	
CShutdownTimer::CShutdownTimer(CConsoleProxyServer& aServer)
	: CTimer(CActive::EPriorityLow), iServer(aServer)
	{
	CActiveScheduler::Add(this);
	}
	
void CShutdownTimer::Start()
	{
	After(KServerShutdownTimer);
	}

void CShutdownTimer::RunL()
	{
	iServer.ShutdownTimerExpired();
	}