diff -r 000000000000 -r 7f656887cf89 libraries/iosrv/client/client_command.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libraries/iosrv/client/client_command.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,445 @@ +// 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 +#include +#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 +