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