--- /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 <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
+