PECengine/CoreUtilsLib2/SrvSrc/PEngServerStarter.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PECengine/CoreUtilsLib2/SrvSrc/PEngServerStarter.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,412 @@
+/*
+* Copyright (c) 2005 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:  Generic thread safe server starter.
+*
+*/
+
+
+//  INCLUDE FILES
+#include "PEngServerStarter.h"
+#include "PEngServerStarterDefs.h"
+#include "TPEngServerParams.h"
+#include "PresenceDebugPrint.h"
+
+#include <E32STD.H>
+#include <f32file.h>
+#include <data_caging_path_literals.hrh>
+
+
+_LIT( KPEngPathDelimiter, "\\" );
+
+
+/**
+ * RSessionBase accessor to give to the PEngServerStarter
+ * access to RSessionBase::CreateSession().
+ *
+ * @since 2.6
+ */
+class RPEngSessionBaseAccessor : public RSessionBase
+    {
+    public: // Constructor
+
+        /**
+         * C++ constructor.
+         *
+         * @since 2.6
+         */
+        inline RPEngSessionBaseAccessor()
+            {
+            }
+
+    public: // New functions
+
+
+        /**
+         * Calls the RSessionBase::CreateSession().
+         *
+         * @since 2.6
+         * @param aServer See RSessionBase::CreateSession().
+         * @param aVersion See RSessionBase::CreateSession().
+         * @param aAsyncMessageSlots See RSessionBase::CreateSession().
+         * @return See RSessionBase::CreateSession().
+         */
+        inline TInt CreateSession( const TDesC& aServer,
+                                   const TVersion& aVersion,
+                                   TInt aAsyncMessageSlots )
+            {
+            return RSessionBase::CreateSession( aServer,
+                                                aVersion,
+                                                aAsyncMessageSlots );
+            }
+    };
+
+
+
+
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+
+
+// -----------------------------------------------------------------------------
+// GenerateFullServerExe()
+// Local helper.
+// Generates full server executable name and path.
+//
+//
+//
+// Param: aServerName - A plain server name for which to generate the fullname.
+// Param: aFullServerPath - On the function return contains full
+//        server path and name.
+// -----------------------------------------------------------------------------
+//
+void GenerateFullServerExe( const TDesC& aServerName, TFileName& aFullServerPath )
+    {
+        {
+        //Get drive (C:)
+        TFileName dllPath;
+        Dll::FileName( dllPath );
+        aFullServerPath.Copy( TParsePtrC( dllPath ).Drive() );
+        }
+
+
+    //Get path (\Xxxx\Xxxx)
+    aFullServerPath.Append( KDC_PROGRAMS_DIR );
+
+    //Fix the path delimeter if missing from path
+    TPtrC pathDelim = aFullServerPath.Right( KPEngPathDelimiter().Length() );
+    if ( pathDelim != KPEngPathDelimiter )
+        {
+        aFullServerPath.Append( KPEngPathDelimiter );
+        }
+
+
+    //Server name + extension (aServer.EXT)
+    aFullServerPath.Append( aServerName );
+    aFullServerPath.Append( KExtDelimiter );
+
+    aFullServerPath.Append( KServerNameExtExe );
+
+    PENG_DP( D_PENG_LIT( "GenerateFullServerExe() [%S]" ), &aFullServerPath );
+    }
+
+
+
+
+// -----------------------------------------------------------------------------
+// ProcessRunning()
+// Local helper.
+// Checks is there server process started from the given
+// exe file (exe or dll).
+//
+//
+// Param: aFullServerExe - Server exe which running status to check.
+//        NOTE!! In THUMB the process name is the name portion of the
+//        filename from which the executable is loaded. In WINS the
+//        thread name is similarly the name portion of the dll filename
+//        (See CreateWinsThread() below) ==> thus here must be used
+//        also the exe/dll as parameter.
+//
+// Return: KErrNotFound - no matching running process found.
+//         KErrNone - one matching running process found.
+//         KErrGeneral - more than one running process found.
+// -----------------------------------------------------------------------------
+//
+TInt ProcessRunning( const TDesC& aFullServerExe )
+    {
+    TFindProcess find;
+    RProcess process;
+
+
+    //Initialize the find
+    TFullName name( TParsePtrC( aFullServerExe ).Name() );
+    name.Append( KMatchAny );
+    find.Find( name );
+
+
+    PENG_DP( D_PENG_LIT( "ProcessRunning() [%S]" ), &name );
+
+    //loop through all of matching processes
+    TInt runningCount = 0;
+    while ( find.Next( name ) == KErrNone )
+        {
+        TInt error = process.Open( find );
+        if ( error != KErrNone )
+            {
+            //if can't open, the process is .. not .. valid
+            PENG_DP( D_PENG_LIT( "ProcessRunning() - Couldn't open process [%S], error[%d]" ), &name, error );
+            continue;
+            }
+
+        TExitType exitType = process.ExitType();
+        process.Close();
+
+        PENG_DP( D_PENG_LIT( "ProcessRunning() - Server process %d found [%S], ExitType[%d] ==> Running[%d]" ),
+                 runningCount, &name, exitType, ( exitType == EExitPending ) );
+
+        //check if the processes is running
+        if ( exitType == EExitPending )
+            {
+            runningCount++;
+            }
+        }
+
+
+    PENG_DP( D_PENG_LIT( "ProcessRunning() [%d] matches found" ), runningCount );
+    switch ( runningCount )
+        {
+        case 0: //No server running
+            {
+            return KErrNotFound;
+            }
+
+        case 1: //One server running
+            {
+            return KErrNone;
+            }
+
+        default:
+            {
+            //More than one server instance running
+            return KErrGeneral;
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// DoLaunchServer()
+// Local helper.
+// Launches the server process and waits it startup.
+//
+// Param: aFullServerExe - The dll / exe from which to launch the server process.
+//        aServerName - The server name to identify the server
+//        aParam1 & 2 - Client given parameters to give to created process.
+//
+// Return: System standard error code.
+//
+// -----------------------------------------------------------------------------
+//
+TInt DoLaunchServer( const TDesC& aFullServerExe,
+                     const TDesC& aServerName,
+                     TInt aParam1,
+                     TInt aParam2 )
+    {
+    PENG_DP( D_PENG_LIT( "DoLaunchServer() [%S] as [%S]" ), &aFullServerExe, &aServerName );
+
+    TInt error( KErrNone );
+    TPEngServerParams startParams( aServerName, aParam1, aParam2 );
+
+
+    //Create thread / process according the platform
+    RProcess process;
+    error = process.Create( aFullServerExe, startParams.AsCommandLine() );
+
+
+    if ( error != KErrNone )
+        {
+        return error;
+        }
+
+
+    //and execute the process and wait it's startup
+    TRequestStatus rendezvousStatus;
+    process.Rendezvous( rendezvousStatus );
+
+    PENG_DP( D_PENG_LIT( "DoLaunchServer() - Waiting for startup or die..." ) );
+    process.Resume();
+    User::WaitForRequest( rendezvousStatus );               // CSI: 94 #
+    error = rendezvousStatus.Int();
+
+    if ( ( error == KErrNone ) &&
+         ( process.ExitType() == EExitPending ) )
+        {
+        //Startup signalled from process ==> server successfully started
+        PENG_DP( D_PENG_LIT( "DoLaunchServer() - Server started" ) );
+        }
+
+    else
+        {
+        //Something failed in server startup
+        TExitCategoryName exitCategory = KNullDesC();
+        exitCategory = process.ExitCategory();
+        PENG_DP( D_PENG_LIT( "DoLaunchServer() - Startup failed: ExitReason[%S, %d], Error[%d]" ),
+                 &exitCategory, process.ExitReason(), error );
+
+        if ( error == KErrNone )
+            {
+            error = KErrServerTerminated;
+            }
+        }
+
+    process.Close();
+
+    return error;
+    }
+
+
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// PEngServerStarter::LaunchServer()
+// Public member function for clients to launch the server process.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt PEngServerStarter::LaunchServer( const TDesC& aServerExeBaseName,
+                                               const TDesC& aServerName,
+                                               TInt aParam1,
+                                               TInt aParam2 )
+    {
+    PENG_DP( D_PENG_LIT( "PEngServerStarter::LaunchServer() [%S]" ), &aServerExeBaseName );
+
+    RMutex launchMutex;
+
+        {
+        // Dynamic mutex name used to allow code share.
+        TName launchMutexName( TParsePtrC( aServerExeBaseName ).Name() );
+        launchMutexName.Append( KPEngLaunchMutexNameExtension );
+
+        // Open or Create mutex to serialize to access to server startup code.
+        // Way below is race condition safe.
+        TInt error( KErrNotFound );
+        while ( error == KErrNotFound )
+            {
+            error = launchMutex.CreateGlobal( launchMutexName );
+            if ( error != KErrAlreadyExists )
+                {
+                break;
+                }
+            error = launchMutex.OpenGlobal( launchMutexName );
+            }
+
+        if ( error != KErrNone )
+            {
+            return error;
+            }
+        }
+
+
+    //Determine the drive for executable
+    TFileName fullServerExe;
+    GenerateFullServerExe( aServerExeBaseName, fullServerExe );
+
+    TInt error;
+    launchMutex.Wait();
+        {
+        //Serialized section
+        error = ProcessRunning( fullServerExe );
+        if ( error == KErrNotFound )
+            {
+            //server not running
+            error = DoLaunchServer( fullServerExe,
+                                    aServerName,
+                                    aParam1,
+                                    aParam2 );
+            }
+        }
+
+    launchMutex.Signal();
+    launchMutex.Close();
+
+    PENG_DP( D_PENG_LIT( "PEngServerStarter::LaunchServer() done[%d]" ), error );
+    return error;
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// PEngServerStarter::ConnectServer()
+// Public member function for clients to connect to server.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt PEngServerStarter::ConnectServer( RSessionBase& aSession,
+                                                const TDesC& aServerName,
+                                                const TVersion& aVersion,
+                                                TInt aAsyncMessageSlots,
+                                                const TDesC& aServerExeBaseName,
+                                                TInt aParam1,
+                                                TInt aParam2 )
+    {
+    if ( aSession.Handle() != KNullHandle )
+        {
+        return KErrInUse;
+        }
+
+    TInt err = KErrGeneral;
+    TInt wait = KPEngSrvConnRetryWait;
+    for ( TInt tries = 0 ; tries < KPEngSrvConnTries ; tries++ )
+        {
+        RPEngSessionBaseAccessor acc;
+        err = acc.CreateSession( aServerName, aVersion, aAsyncMessageSlots );
+        aSession = acc; //session ownership is now on client
+
+        if ( err == KErrNone ||
+             ( err != KErrNotFound && err != KErrServerTerminated ) )
+            {
+            break; // connected ok or something else than missing server
+            }
+
+        // if server not found, try to connect more times
+        if ( ( err == KErrNotFound ) && ( tries < 4 ) )
+            {
+            continue;
+            }
+
+        err = LaunchServer( aServerExeBaseName, aServerName, aParam1, aParam2 );
+        if ( err != KErrNone )
+            {
+            break; //launch failed
+            }
+
+
+        if ( tries > 0 )
+            {
+            //2nd or subsequent try - qive some time for server to startup
+            PENG_DP( D_PENG_LIT( "PEngServerStarter::ConnectServer() - giving time for startup [%d]" ), wait );
+            User::After( wait );    // CSI: 92 #
+            wait = wait + wait;     //On next round wait longer
+            }
+        }
+
+
+    PENG_DP( D_PENG_LIT( "PEngServerStarter::ConnectServer( %d )" ), err );
+    return err;
+    }
+
+
+
+// End of file
+