Migrated ciftest and various fixes from FCL to MCL.
// client_command.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 <fshell/ioutils.h>
#include <fshell/ltkutils.h>
#include "command_base.h"
namespace IoUtils
{
_LIT(KNewLine, "\r\n");
_LIT(KOutgoingMarker, ">");
_LIT(KIncomingMarker, "<");
//
// CServerWatcher.
//
NONSHARABLE_CLASS(CServerWatcher) : public CActive
{
public:
static CServerWatcher* NewL(const TDesC& aServerExeName, CClientBase& aClient);
~CServerWatcher();
void Kill(TInt aReason);
private:
CServerWatcher(CClientBase& aClient);
void ConstructL(const TDesC& aServerExeName);
private: // From CActive.
virtual void RunL();
virtual void DoCancel();
private:
CClientBase& iClient;
RProcess iServerProcess;
};
CServerWatcher* CServerWatcher::NewL(const TDesC& aServerExeName, CClientBase& aClient)
{
CServerWatcher* self = new(ELeave) CServerWatcher(aClient);
CleanupStack::PushL(self);
self->ConstructL(aServerExeName);
CleanupStack::Pop(self);
return self;
}
CServerWatcher::~CServerWatcher()
{
Cancel();
iServerProcess.Close();
}
void CServerWatcher::Kill(TInt aReason)
{
Cancel();
iServerProcess.Kill(aReason);
}
CServerWatcher::CServerWatcher(CClientBase& aClient)
: CActive(CActive::EPriorityStandard), iClient(aClient)
{
CActiveScheduler::Add(this);
}
void CServerWatcher::ConstructL(const TDesC& aServerExeName)
{
_LIT(KWildCard, "*");
TName processName(aServerExeName);
processName.Append(KWildCard);
TFindProcess findProcess(processName);
TFullName name;
StaticLeaveIfErr(findProcess.Next(name), _L("Unable to find server process '%S'"), &aServerExeName);
StaticLeaveIfErr(iServerProcess.Open(findProcess), _L("Unable to open server process '%S'"), &aServerExeName);
if (findProcess.Next(name) != KErrNotFound)
{
StaticLeaveIfErr(KErrArgument, _L("Found more than one instance of '%S'"), &aServerExeName);
}
iServerProcess.Logon(iStatus);
if (iStatus != KRequestPending)
{
User::WaitForRequest(iStatus);
StaticLeaveIfErr(KErrGeneral, _L("Failed to logon to '%S' - %d"), &aServerExeName, iStatus.Int());
}
SetActive();
}
void CServerWatcher::RunL()
{
TExitCategoryName exitCategory(iServerProcess.ExitCategory());
iClient.HandleServerDeath(iServerProcess.ExitType(), iServerProcess.ExitReason(), exitCategory);
}
void CServerWatcher::DoCancel()
{
iServerProcess.LogonCancel(iStatus);
}
//
// CServerReader.
//
NONSHARABLE_CLASS(CServerReader) : public CActive
{
public:
static CServerReader* NewL(RIoReadHandle& aReadHandle, CClientBase& aClient);
~CServerReader();
private:
CServerReader(RIoReadHandle& aReadHandle, CClientBase& aClient);
void ConstructL();
void Queue();
private: // From CActive.
virtual void RunL();
virtual void DoCancel();
private:
RIoReadHandle& iReadHandle;
CClientBase& iClient;
TBuf<0x200> iLine;
};
CServerReader* CServerReader::NewL(RIoReadHandle& aReadHandle, CClientBase& aClient)
{
CServerReader* self = new(ELeave) CServerReader(aReadHandle, aClient);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CServerReader::~CServerReader()
{
Cancel();
}
CServerReader::CServerReader(RIoReadHandle& aReadHandle, CClientBase& aClient)
: CActive(CActive::EPriorityStandard), iReadHandle(aReadHandle), iClient(aClient)
{
CActiveScheduler::Add(this);
}
void CServerReader::Queue()
{
iLine.Zero();
iReadHandle.Read(iLine, iStatus);
SetActive();
}
void CServerReader::ConstructL()
{
iReadHandle.SetReadModeL(RIoReadHandle::ELine);
iReadHandle.SetLineSeparatorL(KNewLine());
Queue();
}
void CServerReader::RunL()
{
TInt err = iStatus.Int();
if (err == KErrEof)
{
iClient.HandleServerReadComplete(KErrServerTerminated, iLine);
}
else
{
iClient.HandleServerReadComplete(err, iLine);
}
Queue();
}
void CServerReader::DoCancel()
{
iReadHandle.ReadCancel();
}
//
// CServerWriter.
//
NONSHARABLE_CLASS(CServerWriter) : public CActive
{
public:
static CServerWriter* NewL(RIoWriteHandle& aWriteHandle, CClientBase& aClient);
~CServerWriter();
void Write(const TDesC& aLine);
private:
CServerWriter(RIoWriteHandle& aWriteHandle, CClientBase& aClient);
private: // From CActive.
virtual void RunL();
virtual void DoCancel();
private:
RIoWriteHandle& iWriteHandle;
CClientBase& iClient;
HBufC* iBuf;
};
CServerWriter* CServerWriter::NewL(RIoWriteHandle& aWriteHandle, CClientBase& aClient)
{
return new(ELeave) CServerWriter(aWriteHandle, aClient);
}
CServerWriter::~CServerWriter()
{
Cancel();
delete iBuf;
}
CServerWriter::CServerWriter(RIoWriteHandle& aWriteHandle, CClientBase& aClient)
: CActive(CActive::EPriorityStandard), iWriteHandle(aWriteHandle), iClient(aClient)
{
CActiveScheduler::Add(this);
}
void CServerWriter::Write(const TDesC& aLine)
{
ASSERT(!IsActive());
TInt bufferRequired = aLine.Length();
TBool newLineRequired(EFalse);
if ((aLine.Length() < KNewLine().Length()) || (aLine.Right(KNewLine().Length()) != KNewLine))
{
newLineRequired = ETrue;
bufferRequired += KNewLine().Length();
}
if (iBuf && (iBuf->Des().MaxLength() < bufferRequired))
{
iBuf = iBuf->ReAllocL(bufferRequired);
}
else
{
iBuf = HBufC::NewL(bufferRequired);
}
TPtr ptr(iBuf->Des());
ptr.Copy(aLine);
if (newLineRequired)
{
ptr.Append(KNewLine);
}
iWriteHandle.Write(*iBuf, iStatus);
SetActive();
}
void CServerWriter::RunL()
{
iClient.HandleServerWriteComplete(iStatus.Int());
}
void CServerWriter::DoCancel()
{
iWriteHandle.WriteCancel();
}
EXPORT_C CClientBase::CClientBase(TUint aFlags, const TDesC& aServerExeName, const TDesC& aPersistentConsoleName, const TDesC& aServerPrompt)
: CCommandBase(EManualComplete | aFlags), iServerExeName(aServerExeName), iPersistentConsoleName(aPersistentConsoleName), iServerPrompt(aServerPrompt)
{
}
EXPORT_C CClientBase::~CClientBase()
{
delete iCommand;
delete iServerReader;
delete iServerWriter;
delete iServerWatcher;
iServerWritePipe.Close();
iServerWriteHandle.Close();
iServerReadPipe.Close();
iServerReadHandle.Close();
iPcons.Close();
iServerProcess.Close();
iLines.ResetAndDestroy();
}
_LIT(KWritePipeNameFmt, "%S client->server pipe");
_LIT(KWriterNameFmt, "%S server writer");
_LIT(KReadPipeNameFmt, "%S server->client pipe");
_LIT(KReaderNameFmt, "%S server reader");
EXPORT_C void CClientBase::DoRunL()
{
TInt err = iPcons.OpenByName(IoSession(), iPersistentConsoleName);
if (err==KErrNotFound)
{
if (iVerbose)
{
Printf(_L("'%S' not found, creating...\r\n"), &iPersistentConsoleName);
}
LeaveIfErr(iPcons.Create(IoSession(), iPersistentConsoleName, iPersistentConsoleName), _L("Couldn't create persistent console '%S'"), &iPersistentConsoleName);
TRAPL(iServerProcess.CreateL(iServerExeName, KNullDesC(), IoSession(), iPcons, &Env()), _L("Couldn't create server process"));
}
else
{
LeaveIfErr(err, _L("Cannot open persistent console '%S'"), &iPersistentConsoleName);
}
iServerWatcher = CServerWatcher::NewL(iServerExeName, *this);
TName objName;
iServerWritePipe.CreateL(IoSession());
objName.AppendFormat(KWritePipeNameFmt, &Name());
IoSession().SetObjectNameL(iServerWritePipe.SubSessionHandle(), objName);
iServerWriteHandle.CreateL(IoSession());
objName.Zero();
objName.AppendFormat(KWriterNameFmt, &Name());
IoSession().SetObjectNameL(iServerWriteHandle.SubSessionHandle(), objName);
iServerWriteHandle.SetModeL(RIoWriteHandle::EText);
iServerWritePipe.AttachL(iServerWriteHandle);
// attach the pcons reader to the other end of our server write pipe
LeaveIfErr(iPcons.AttachReader(iServerWritePipe, RIoPersistentConsole::EDetachOnHandleClose), _L("Cannot connect reader to persistent console %S"), &iPersistentConsoleName);
iServerWriter = CServerWriter::NewL(iServerWriteHandle, *this);
iServerReadPipe.CreateL(IoSession());
objName.Zero();
objName.AppendFormat(KReadPipeNameFmt, &Name());
IoSession().SetObjectNameL(iServerReadPipe.SubSessionHandle(), objName);
iServerReadHandle.CreateL(IoSession());
objName.Zero();
objName.AppendFormat(KReaderNameFmt, &Name());
IoSession().SetObjectNameL(iServerReadHandle.SubSessionHandle(), objName);
iServerReadPipe.AttachL(iServerReadHandle, RIoEndPoint::EForeground);
// attach the pcons writer to the other end of our server read pipe
LeaveIfErr(iPcons.AttachWriter(iServerReadPipe, RIoPersistentConsole::EDetachOnHandleClose), _L("Cannot connect writer to persistent console %S"), &iPersistentConsoleName);
iServerReader = CServerReader::NewL(iServerReadHandle, *this);
if (iServerProcess.Process().Handle() != KNullHandle && iServerProcess.Process().Handle() != RProcess().Handle())
{
// We created a new server process, but it's not yet been resumed.
iServerProcess.Detach(); // Note, iServerWatch has already logged onto the process so there's no need to use RChildProcess::Run.
iWaitingForServerPrompt = ETrue;
}
else
{
// The server was already running - no need to wait for a prompt, go ahead and write the command.
SendCommand();
}
}
EXPORT_C void CClientBase::ArgumentsL(RCommandArgumentList& aArguments)
{
_LIT(KCommand, "command");
if (UsingCif()) // Test this dynamically for the time being because not all sub-classes have been migrated to CIFs.
{
aArguments.AppendStringL(iCommand, KCommand);
}
else
{
_LIT(KCommandDescription, "The command to run.");
aArguments.AppendStringL(iCommand, KCommand, KCommandDescription, KValueTypeFlagLast);
}
}
EXPORT_C void CClientBase::HandleLeave(TInt aError)
{
CCommandBase::HandleLeave(aError);
}
void CClientBase::HandleServerReadComplete(TInt aError, TDes& aLine)
{
if (aError == KErrEof)
{
Complete(KErrNone);
}
else if (aError)
{
iServerWatcher->Kill(KErrAbort);
Complete(aError, _L("Failed to read server response"));
}
else if (aLine == iServerPrompt)
{
if (iWaitingForServerPrompt)
{
iWaitingForServerPrompt = EFalse;
SendCommand();
}
else
{
TRAPD(err, HandleServerResponseL(iLines));
Complete(err);
}
}
else
{
if (iVerbose)
{
Write(KIncomingMarker);
Write(aLine);
}
if (!iWaitingForServerPrompt)
{
aLine.TrimRight();
HBufC* buf = aLine.AllocLC();
iLines.AppendL(buf);
CleanupStack::Pop(buf);
}
}
}
void CClientBase::HandleServerWriteComplete(TInt aError)
{
if (aError)
{
iServerWatcher->Kill(KErrAbort);
Complete(aError, _L("Failed to write command to server"));
}
}
void CClientBase::HandleServerDeath(TExitType aExitType, TInt aExitReason, const TDesC& aExitCategory)
{
if (aExitType == EExitPanic)
{
Complete(KErrServerTerminated, _L("Server '%S' PANIC - %S %d"), &iServerExeName, &aExitCategory, aExitReason);
}
else if (aExitReason)
{
Complete(aExitReason, _L("Server '%S' exitied abnormally"), &iServerExeName);
}
else
{
Complete();
}
}
void CClientBase::SendCommand()
{
if (iVerbose)
{
Write(KOutgoingMarker);
Write(*iCommand);
Write(KNewLine);
}
iServerWriter->Write(*iCommand);
}
} // namespace IoUtils