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