cryptomgmtlibs/securitycommonutils/source/scsclient/scsclientbase.cpp
changeset 8 35751d3474b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cryptomgmtlibs/securitycommonutils/source/scsclient/scsclientbase.cpp	Thu Sep 10 14:01:51 2009 +0300
@@ -0,0 +1,306 @@
+/*
+* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+* Generic client-side code for client-server interaction.
+* Attempts to establish a connection to a session counting server,
+* starting the process if required.
+*
+*/
+
+
+/**
+ @file
+*/
+
+#include <scs/scsclient.h>
+
+#include <scs/scscommon.h>
+
+using namespace ScsImpl;
+
+
+EXPORT_C RScsClientBase::RScsClientBase()
+/**
+	This constructor is protected to ensure this class is not
+	instantiated directly.
+ */
+:	RSessionBase()
+	{
+	// empty.
+	}
+
+EXPORT_C void RScsClientBase::Close()
+/**
+	This method should be used in preference to RScsSessionBase::Close
+	because it sends a message to cancel any outstanding requests on the
+	session or its subsessions.
+ */
+	{
+	if(iHandle)
+		{
+		RSessionBase::SendReceive(EPreCloseSession);
+		RSessionBase::Close();
+		}
+	}
+
+TInt RScsClientBase::StartServerProcess(const TDesC& aExeName, const TUidType& aFullExeUid)
+/**
+	This function is defined for the convenience of subclasses which need to start
+	a server process before they can connect to the server.
+
+	@param	aExeName		Executable which hosts the server.
+	@param	aFullExeUid		The server executable's full UID.  This is used to ensure the
+							intended executable is started, and not another executable
+							with the same name.
+	@return					Symbian OS error code.  KErrNone indicates success, and any other
+							value indicates failure.
+	@pre This function should only be called by Connect(const TVersion&) if the server is
+		not already running.
+ */
+	{
+	RProcess pr;
+	TInt r = pr.Create(aExeName, /* aCommand */ KNullDesC, aFullExeUid);
+	if (r != KErrNone)
+		return r;
+
+	TRequestStatus rs;
+	pr.Rendezvous(rs);
+	if (rs != KRequestPending)
+		r = rs.Int();
+	else
+		{
+		pr.Resume();
+		User::WaitForRequest(rs);
+		if (rs.Int()==KErrAlreadyExists)
+			r=KErrAlreadyExists;
+		else
+			r = (pr.ExitType() == EExitPending) ? rs.Int() : KErrGeneral;
+		}
+
+	pr.Close();
+	return r;
+	}
+
+EXPORT_C TInt RScsClientBase::Connect(
+	const TDesC& aSvrName, const TVersion& aReqVer, const TDesC& aExeName, const TUidType& aFullExeUid)
+/**
+	Attempt to connect to the named server.  If the server is not available then attempt
+	to start its hosting process.
+
+	@param	aSvrName		Name of server to connect to.
+	@param	aReqVer			Required server version.
+	@param	aExeName		Executable which hosts the server.  This function will launch this
+							executable if the server is not running.
+	@param	aFullExeUid		The server executable's full UID.  This ensures the intended
+							executable is started, and not another executable with the same name.
+	@return					Symbian OS error code.  KErrNone indicates success,
+							and any other value indicates failure.
+ */
+	{
+	TInt retries = 2;		// number of remaining retries
+
+	for (;;)
+		{
+		TInt r = CreateSession(aSvrName, aReqVer);
+		
+		// if connected then finished
+		if (r == KErrNone)
+			return r;
+
+		// if any reason other than server not available then abort
+		if (r != KErrNotFound && r != KErrServerTerminated)
+			return r;
+
+		if (--retries == 0)
+			return r;
+
+		r = StartServerProcess(aExeName, aFullExeUid);
+		if (r != KErrNone && r != KErrAlreadyExists)
+			return r;
+		}	// for (;;)
+	}
+
+// -------- server heap checking --------
+
+EXPORT_C TInt RScsClientBase::SetServerHeapFail(TInt aRate)
+/**
+	Start marking the server heap and set a deterministic
+	fail rate.  This should matched with a call to EndServerHeapFail.
+	
+	This function is empty in release builds.
+	
+	@param	aRate			Number of allocations after which allocation
+							should fail on the server heap.
+	@see EndServerHeapFail
+	@see __UHEAP_MARK
+	@see __UHEAP_SETFAIL
+ */
+	{
+#ifndef _DEBUG
+	(void) aRate;
+	return KErrNone;
+#else
+	TIpcArgs ipc(aRate);
+	return RSessionBase::SendReceive(ScsImpl::EUHeapSetFail, ipc);
+#endif
+	}
+
+EXPORT_C TInt RScsClientBase::ResetServerHeapFail()
+/**
+	Finish marking the server heap and reset the failure rate.
+	This should match a previous call to SetServerHeapFail.
+
+	If there is a heap imbalance, then the server will be panicked.
+
+	This function is empty in release builds.
+	
+	@see SetServerHeapFail
+	@see __UHEAP_MARKEND
+	@see __UHEAP_RESET
+ */
+	{
+#ifdef _DEBUG
+	return RSessionBase::SendReceive(ScsImpl::EUHeapResetFail);	
+#else
+	return KErrNone;
+#endif
+	}
+
+// -------- passing arguments to a server-side session --------
+
+EXPORT_C TInt RScsClientBase::ShutdownServer()
+/**
+DEBUG USE ONLY - Tells the server to shutdown down ASAP, and block
+until it has done so. This also closes the current session.
+
+If the server is not configured to use a inactivity shutdown timer,
+this will fail with KErrNotSupported.
+
+nb. You may still need to call the Close function of a derived class
+to ensure it gets to cleanup...
+
+	@return					Symbian OS error code where KErrNone indicates
+							success and any other value indicates failure.
+ */
+	{
+	// Find servers PID
+	TPckgBuf<TProcessId> idBuf;
+	TIpcArgs args(&idBuf);
+	TInt r = RSessionBase::SendReceive(ScsImpl::EGetServerPid, args);
+	if(r != KErrNone) return r;
+
+	// Open a handle for the server thread
+	RProcess server;
+	r = server.Open(idBuf(), EOwnerThread);
+	if(r != KErrNone) return r;
+	
+	// Logon to the server process to spot when it exits
+	TRequestStatus rs;
+	server.Logon(rs);
+
+	// Ask the server to exit ASAP
+	r = RSessionBase::SendReceive(ScsImpl::EShutdownAsap);
+	if(r != KErrNone)
+		{
+		(void) server.LogonCancel(rs);
+		server.Close();
+		return r;
+		}
+
+	// Close our session
+	Close();
+
+	// Wait for the server to finish shutting down
+	User::WaitForRequest(rs); // nb. we do not care what code it shutdown with.
+
+	// Close our server process handle
+	server.Close();
+
+	return KErrNone;
+	}
+
+// -------- passing arguments to a server-side session --------
+
+EXPORT_C TInt RScsClientBase::CallSessionFunction(TInt aFunction) const
+/**
+	Send a command to the corresponding server-side session.  The
+	subclass uses this function instead of directly calling
+	RSubSessionBase::SendReceive because it adds the SCS code
+	which marks this as an ordinary session call.
+	
+	@param	aFunction		Function identifier.  Bits 31:24 must be zero,
+							because they are reserved for SCS commands.
+	@return					Error code with which the server completed the request.
+ */
+	{
+	__ASSERT_DEBUG(! ScsFieldUsed(aFunction), ClientSidePanic(EScsClNoArgsSessUsedScs));
+	
+	TInt f = ECallSessionFunc | aFunction;
+	return RSessionBase::SendReceive(f);
+	}
+
+EXPORT_C TInt RScsClientBase::CallSessionFunction(TInt aFunction, const TIpcArgs& aArgs) const
+/**
+	Send a command to the corresponding server-side session.  The
+	subclass uses this function instead of directly calling
+	RSubSessionBase::SendReceive because it adds the SCS code which
+	marks this as an ordinary session call.
+
+	@param	aFunction		Session function identifier.  Bits 31:24 must be zero,
+							because they are reserved for SCS commands.
+	@param	aArgs			Standard IPC arguments.
+	@return					Error code with which the server completed the request.
+ */
+	{
+	__ASSERT_DEBUG(! ScsFieldUsed(aFunction), ClientSidePanic(EScsClArgsSessUsedScs));
+	
+	TInt f = ECallSessionFunc | aFunction;
+	return RSessionBase::SendReceive(f, aArgs);
+	}
+
+EXPORT_C void RScsClientBase::CallSessionFunction(TInt aFunction, const TIpcArgs& aArgs, TRequestStatus& aStatus) const
+/**
+	Send the supplied function identifier and arguments to the server-side
+	session.  The subclass uses this function instead of directly calling
+	RSubSessionBase::SendReceive because it adds the SCS code which marks
+	this as an ordinary session call.
+
+	@param	aFunction		Session function identifier.  Bits 31:24 must be zero,
+							because they are reserved for SCS commands.
+	@param	aArgs			Standard IPC arguments.
+	@param	aStatus			This will be completed by the server when it has
+							finished handling the function.
+ */
+	{
+	__ASSERT_DEBUG(! ScsFieldUsed(aFunction), ClientSidePanic(EScsClArgsSessAsyncUsedScs));
+	
+	TInt f = ECallSessionFunc | aFunction;
+	RSessionBase::SendReceive(f, aArgs, aStatus);
+	}
+
+EXPORT_C void RScsClientBase::CancelSessionFunction(TInt aFunction) const
+/**
+	Cancel an outstanding session request.  This has no effect if the
+	request is not outstanding.
+	
+	@param	aFunction		Implementation function.  This must be the
+							same value that was supplied to CallSessionFunction.
+ */
+	{
+	__ASSERT_DEBUG(! ScsFieldUsed(aFunction), ClientSidePanic(EScsClCancelSessUsedScs));
+	
+	TInt f = ECancelSessionFunc | aFunction;
+	RSessionBase::SendReceive(f);
+	}
+