imservices/instantmessagingcache/imcacheclient/src/imcacheprocessstarter.cpp
author hgs
Wed, 03 Nov 2010 09:32:20 +0530
changeset 51 61fad867f68e
permissions -rw-r--r--
201041

/*
* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "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:  start the server
*
*/


#include "imcacheprocessstarter.h"
// logs
#include "imcachedebugtrace.h"
// system includes
#include <e32std.h>
#include <f32file.h>


// CONSTANTS
_LIT( KEka2ExeDir,"\\sys\\bin\\");
_LIT( KEka2LaunchMutexExt, "[lMtx]" );
const TInt KEka2SrvConnTries = 7;
const TInt KEka2SrvConnInitialRetryWait = 500; //MicroSeconds => 0.0005s


// ==============================================================
// ====================== HELPER CLASS ==========================
// ==============================================================

/**
 * RSessionBase accessor to give to the ProcessStarter
 * access to RSessionBase::CreateSession().
 */
class REka2SessionBaseAccessor : public RSessionBase
    {
    public: // Constructor
        inline REka2SessionBaseAccessor()
            {
            }

    public: // New functions

        /**
         * Public access to RSessionBase::CreateSession().
         */
        inline TInt CreateSession( const TDesC& aServer,
                                   const TVersion& aVersion,
                                   TInt aAsyncMessageSlots )
            {
            return RSessionBase::CreateSession( aServer,
                                                aVersion,
                                                aAsyncMessageSlots );
            }
    };


// ==============================================================
// ====================== PROCESSSTARTER ========================
// ==============================================================

// --------------------------------------------------------------
// IMCacheProcessStarter::FullExePathForClientLocation()
// --------------------------------------------------------------
//
void IMCacheProcessStarter::FullExePathForClientLocation(
    const TDesC& aExeName,
    TFileName& aFullExePath )
    {
	TRACE( T_LIT("IMCacheProcessStarter::FullExePathForClientLocation begin") );
    //Get drive (C:) where this client code is installed
        {
        TFileName tmp;
        Dll::FileName( tmp );
        aFullExePath.Copy( TParsePtrC( tmp ).Drive() );
        }

    //Build the rest from the exe path
    aFullExePath.Append( KEka2ExeDir );
    aFullExePath.Append( aExeName );
    TRACE( T_LIT("IMCacheProcessStarter::FullExePathForClientLocation end") );
    }

// --------------------------------------------------------------
// IMCacheProcessStarter::StartInstance()
// --------------------------------------------------------------
//
TInt IMCacheProcessStarter::StartInstance(
    const TDesC& aFullExePath,
    const TDesC& aCommand )
    {
    TRACE( T_LIT("IMCacheProcessStarter::StartInstance begin") );
    RMutex launchMutex;
    TInt error = KErrNotFound;

        {
        // Dynamic mutex name used to allow code share
        TName launchMutexName( TParsePtrC( aFullExePath ).Name() );
        launchMutexName.Append( KEka2LaunchMutexExt );

        // Open or Create mutex to serialize to access to server startup code.
        // (race condition safe way)
        while( error == KErrNotFound )
            {
            error = launchMutex.CreateGlobal( launchMutexName );
            if( error != KErrAlreadyExists )
                {
                break;
                }
            error = launchMutex.OpenGlobal( launchMutexName );
            }

        if( error != KErrNone )
            {
            TRACE( T_LIT("IMCacheProcessStarter::StartInstance end") );
            return error;
            }
        }


    launchMutex.Wait();

    //Serialized access
    error = IMCacheProcessStarter::DoStartInstance( aFullExePath,
                                             aCommand );

    launchMutex.Signal();
    launchMutex.Close();
	TRACE( T_LIT("IMCacheProcessStarter::StartInstance end") );
    return error;
    }

// --------------------------------------------------------------
// IMCacheProcessStarter::ConnectToServer()
// --------------------------------------------------------------
//
TInt IMCacheProcessStarter::ConnectToServer(
    const TDesC& aFullExePath,
    const TDesC& aCommand,
    RSessionBase& aSessionToConnect,
    const TDesC& aServerName,
    const TVersion& aClientVersion,
    TInt aAsyncMessageSlots )
    {
    TRACE( T_LIT("IMCacheProcessStarter::ConnectToServer begin") );
    if( aSessionToConnect.Handle() != KNullHandle )
        {
        return KErrInUse;
        }

    TInt err = KErrNone;
    TInt startupWait = KEka2SrvConnInitialRetryWait;

    //Server connect and launch loop
    for( TInt trie = 0 ; trie < KEka2SrvConnTries ; trie++ )
        {
        REka2SessionBaseAccessor acc;
        err = acc.CreateSession( aServerName,
                                 aClientVersion,
                                 aAsyncMessageSlots );

        if( err == KErrNone )
            {
            //session ownership is now on client
            aSessionToConnect = acc;
            return KErrNone;
            }

        else if( ( err == KErrNotFound ) ||
                 ( err == KErrServerTerminated ) )
            {
            //Server missing or died when connecting
            //Start a new server
            err = IMCacheProcessStarter::StartInstance( aFullExePath,
                                                 aCommand );

            //If process exist already, then all is fine
            //(some other process started it between the origical connect and launch trie)
            if( err == KErrAlreadyExists )
                {
                err = KErrNone;
                }

            //If server process start failed, bail out.
            if( err != KErrNone )
                {
                return err;
                }

            //If this is 2nd or subsequent try,
            //give some time for server to startup
            if( trie > 0 )
                {
                // Code scanner warning : Use of User::After (id:92)
                // it is required to be used here
                User::After( startupWait ); // CSI: 92 # See above
                startupWait = 2 * startupWait;
                }
            }

        else
            {
            //Server process start failed. Bail out.
            return err;
            }
        }
	TRACE( T_LIT("IMCacheProcessStarter::ConnectToServer end") );
    return err;
    }

// --------------------------------------------------------------
// IMCacheProcessStarter::DoStartServerInstance()
// --------------------------------------------------------------
//
TInt IMCacheProcessStarter::DoStartInstance(
    const TDesC& aFullExePath,
    const TDesC& aCommand )
    {
    TRACE( T_LIT("IMCacheProcessStarter::DoStartInstance begin") );
    TInt error = KErrNone;

    //Create process
    RProcess process;
    error = process.Create( aFullExePath, aCommand );

    if( error == KErrNone )
        {
       
            TRequestStatus rendezvousStatus;
            process.Rendezvous( rendezvousStatus );

            process.Resume();
            // Codescanner warning: user of User::WaitForRequest (Id:94)
            // it is required to use at server startup
            User::WaitForRequest( rendezvousStatus ); // CSI: 94 # See above
            error = rendezvousStatus.Int();

            if( process.ExitType() != EExitPending )
                {
                //Something failed in server startup
                //Force the error code to be always something
                //else than KErrNone
                if( error == KErrNone )
                    {
                    error = KErrServerTerminated;
                    }
                }
           
        }

    process.Close();
	TRACE( T_LIT("IMCacheProcessStarter::DoStartInstance end") );
    return error;
    }

// END OF FILE