--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/engine/src/catalogsclientserverclientsession.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,696 @@
+/*
+* Copyright (c) 2006 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: Implementation of RCatalogsClientServerClientSession
+*
+*/
+
+
+#include "catalogsclientserverclientsession.h"
+#include "catalogsclientserverserver.h"
+#include "catalogsserverdefines.h"
+#include "catalogsclientserverasynctask.h"
+#include "catalogsclientserverallocutils.h"
+#include "catalogsdebug.h"
+
+// Amount of attempts to create and connect to server before giving up
+const TInt KCatalogsServerStartAttempts( 5 );
+// Amount of sleep between retries
+const TInt KRetryInterval( 100000 ); // tenth of a second
+
+// Amount of time before we quit on waiting on the semaphore and go on
+const TInt KSemaphoreTimeout( 1000000 * 3 ); // 3 seconds
+
+// ======== LOCAL FUNCTIONS ========
+
+static TInt CreateServerProcess()
+ {
+ DLTRACEIN((""));
+ RProcess server;
+
+ TInt result = server.Create( KCatalogsServerFilename, KNullDesC );
+ if ( result != KErrNone )
+ {
+ DLERROR(( "Failed to create server process: err %d", result ));
+ DLTRACEOUT(( "%d", result ));
+ return result;
+ }
+
+ // Resume server thread and close handle
+ server.Resume();
+ server.Close();
+
+ return KErrNone;
+ }
+
+static TInt StartServer()
+ {
+ DLTRACEIN((""));
+
+ // Check if the server is already running
+ TFindServer findServer( KCatalogsServerName );
+ TFullName name;
+
+ TInt result = findServer.Next( name );
+ if ( result == KErrNone )
+ {
+ // Server is running
+ return KErrNone;
+ }
+
+ // Create a semaphore so we can wait while the server starts
+ RSemaphore semaphore;
+ result = semaphore.CreateGlobal( KCatalogsServerSemaphoreName, 0 );
+ if ( result != KErrNone )
+ {
+ DLERROR(( "Failed to create semaphore: err %d", result ));
+ DLTRACEOUT(( "%d", result ));
+ return result;
+ }
+
+ // Create new Engine service process
+ result = CreateServerProcess();
+ if ( result != KErrNone )
+ {
+ DLTRACEOUT(( "%d", result ));
+ semaphore.Close();
+ return result;
+ }
+
+ // Wait while the server starts, if the timeout occurs, we can
+ // assume the server didn't start correctly
+ TInt err = semaphore.Wait( KSemaphoreTimeout );
+
+ // Semaphore has been signaled, close and return
+ semaphore.Close();
+
+ DLTRACEOUT(("error: %d", err ));
+ return err;
+ }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+
+RCatalogsClientServerClientSession::RCatalogsClientServerClientSession() :
+ iSessionStatus( EClosed )
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// This is function to create server process if it does not exist and to
+// to connect to the server. Notice that if the current server is going
+// down the StartServer() still does not create a new server. If this happens
+// then the CreateSession returns -15. If this happens we try the
+// server creation for a few times. We also have a sleep between tries
+// that halts this thread.
+// ---------------------------------------------------------------------------
+//
+TInt RCatalogsClientServerClientSession::Connect( TUid aClientUid )
+ {
+ DLTRACEIN((""));
+ if ( iSessionStatus == EOpen )
+ {
+ return KErrNone;
+ }
+
+ TInt err( KErrNone );
+ TInt startTryCounter( 0 );
+ while( startTryCounter < KCatalogsServerStartAttempts )
+ {
+ DLINFO(( "Trying to start server, try nro: %d", startTryCounter + 1 ));
+ err = KErrNone; // reset before a new try
+
+ // StartServer() does not return error even if the current server is
+ // shutting down.
+ err = StartServer();
+ DLINFO(( "startserver %d", err ));
+ if ( KErrNone == err )
+ {
+ // If current server is dying, this returns error
+ err = CreateSession(
+ KCatalogsServerName,
+ Version(),
+ KCatalogsDefaultMessageSlots );
+ DLINFO(( "createsession %d", err ));
+ if ( err == KErrNone )
+ {
+ iSessionStatus = EOpen;
+
+ TIpcArgs args( aClientUid.iUid );
+ err = SendSync( ECatalogsCreateContext, args );
+ }
+ }
+
+ if ( err == KErrNone )
+ {
+ break;
+ }
+
+ ++startTryCounter;
+ DLINFO(( "Did not succeed in connecting, entering sleep... " ));
+ User::After( KRetryInterval ); // This halts the whole thread
+ DLINFO(( "Retrying connect." ));
+ }
+
+ DLTRACEOUT(("err: %d", err));
+ return err;
+ }
+
+void RCatalogsClientServerClientSession::Disconnect()
+ {
+ DLTRACEIN((""));
+ // Before cleaning up the iTasks, we ensure that if there
+ // possibly still are pending tasks, server-side objects don't
+ // complete them anymore. Also we assume that everything
+ // possible is already done to ensure that there are no
+ // tasks pending.
+ if ( iSessionStatus == EOpen )
+ {
+ // Have to be sure so that we don't try to
+ // send message using invalid handle
+ TIpcArgs args = TIpcArgs();
+ SendSync( ECatalogsClientSideDown, args );
+ }
+
+ // We trust that disconnect is always said, so contents of
+ // iTasks is destroyed here
+ iTasks.ResetAndDestroy();
+
+ RHandleBase::Close(); //close handle (this) to the server-side session
+
+ iSessionStatus = EClosed;
+ DLTRACEOUT((""));
+ }
+
+// ---------------------------------------------------------------------------
+// Creation of a provider uses a internal message type
+// to tell the server-side to create the desired provider.
+// ---------------------------------------------------------------------------
+//
+void RCatalogsClientServerClientSession::CreateProvider(
+ TInt aUid,
+ TRequestStatus& aStatus,
+ TInt& aHandle,
+ TUint32 aOptions )
+ {
+ DLTRACEIN((""));
+
+ aStatus = KRequestPending;
+
+ CCatalogsClientServerAsyncTask* task = NULL;
+ TRAPD( error, GetAsyncTaskL( task ) );
+ if ( error != KErrNone )
+ {
+ // This is called before setActive in client?
+ // Is that a problem?
+ DLTRACEOUT(("error=%X",error));
+ TRequestStatus* status = &aStatus;
+ User::RequestComplete( status, error );
+ return;
+ }
+
+ DLTRACE(("CreateProvider using task"));
+ task->CreateProvider( aUid, aStatus, aHandle, aOptions );
+
+ DLTRACEOUT(("RCatalogsClientServerClientSession end"));
+ }
+
+// ---------------------------------------------------------------------------
+// Replace all asynchronous SendReceives in this class with this
+// SendAsync so we get all asynchronous sending into one function
+// ---------------------------------------------------------------------------
+//
+void RCatalogsClientServerClientSession::SendAsync(
+ TCatalogsServerFunction aMessageType,
+ const TIpcArgs& aArgs,
+ TRequestStatus& aStatus )
+ {
+ aStatus = KRequestPending;
+ SendReceive( aMessageType, aArgs, aStatus );
+ }
+
+// ---------------------------------------------------------------------------
+// Replace all synchronous SendReceives in this class with this
+// SendSync so we get all synchronous sending into one function
+// ---------------------------------------------------------------------------
+//
+TInt RCatalogsClientServerClientSession::SendSync(
+ TCatalogsServerFunction aMessageType,
+ const TIpcArgs& aArgs )
+ {
+ return SendReceive( aMessageType, aArgs );
+ }
+
+void RCatalogsClientServerClientSession::TaskCompleted(
+ CCatalogsClientServerAsyncTask* aCompletedTask )
+ {
+ DLTRACEIN((""));
+ TInt index( iTasks.Find( aCompletedTask ) );
+ iTasks.Remove( index );
+ delete aCompletedTask;
+#ifdef CATALOGS_BUILD_CONFIG_DEBUG
+/*
+ RThread currentThread;
+
+ TInt semCount = currentThread.RequestCount();
+ DLTRACE(("semCount: %d", semCount ));
+ currentThread.Close();
+*/
+#endif
+
+ DLTRACEOUT((""));
+ }
+
+TInt RCatalogsClientServerClientSession::DeleteIncompleteMessage(
+ TInt aHandle )
+ {
+ DLTRACEIN((""));
+ TPckgBuf<TInt> handle( aHandle );
+ TIpcArgs args = TIpcArgs();
+ args.Set( 1, &handle );
+ return SendReceive( ECatalogsRemoveIncompleteMessage,
+ args );
+ }
+
+
+TVersion RCatalogsClientServerClientSession::Version() const
+ {
+ return TVersion( KCatalogsServerMajorVersionNumber,
+ KCatalogsServerMinorVersionNumber,
+ KCatalogsServerBuildVersionNumber );
+ }
+
+
+TInt RCatalogsClientServerClientSession::SendSync( TInt aFunction,
+ const TDesC8& aInput,
+ TDes8& aOutput,
+ TInt aHandle )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+ // Actually these would not need to be in TPckgBuf
+ // when they are not used for returning purposes.
+ TPckgBuf<TInt> function( aFunction );
+ TPckgBuf<TInt> handle( aHandle );
+
+ return SendReceive( ECatalogsExternalMessage,
+ TIpcArgs( &function,
+ &handle,
+ &aInput,
+ &aOutput ));
+ }
+
+
+TInt RCatalogsClientServerClientSession::SendSync( TInt aFunction,
+ const TDesC16& aInput,
+ TDes16& aOutput,
+ TInt aHandle )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+ // Actually these would not need to be in TPckgBuf
+ // when they are not used for returning purposes.
+ TPckgBuf<TInt> function( aFunction );
+ TPckgBuf<TInt> handle( aHandle );
+
+ return SendReceive( ECatalogsExternalMessage,
+ TIpcArgs( &function,
+ &handle,
+ &aInput,
+ &aOutput ));
+ }
+
+
+TInt RCatalogsClientServerClientSession::SendSync( TInt aFunction,
+ const TDesC16& aInput,
+ TInt& aOutputInt,
+ TInt aHandle )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+
+ // Actually these would not need to be in TPckgBuf
+ // when they are not used for returning purposes.
+ TPckgBuf<TInt> function( aFunction );
+ TPckgBuf<TInt> handle( aHandle );
+
+ TPckgBuf<TInt> integerReturnBuf;
+
+ DLTRACE(("Sending message to server"));
+
+ TInt returnValue = SendReceive( ECatalogsExternalMessage,
+ TIpcArgs( &function,
+ &handle,
+ &aInput,
+ &integerReturnBuf ));
+
+ DLTRACE(("Done, err: %i, handle: %d", returnValue, aHandle ));
+
+ aOutputInt = integerReturnBuf();
+ return returnValue;
+ }
+
+TInt RCatalogsClientServerClientSession::SendSync( TInt aFunction,
+ const TDesC8& aInput,
+ TInt& aOutputInt,
+ TInt aHandle )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+
+ // Actually these would not need to be in TPckgBuf
+ // when they are not used for returning purposes.
+ TPckgBuf<TInt> function( aFunction );
+ TPckgBuf<TInt> handle( aHandle );
+
+ TPckgBuf<TInt> integerReturnBuf;
+
+ DLTRACE(("Sending message to server"));
+
+ TInt returnValue = SendReceive( ECatalogsExternalMessage,
+ TIpcArgs( &function,
+ &handle,
+ &aInput,
+ &integerReturnBuf ));
+
+ DLTRACE(("Done, err: %i, handle: %d", returnValue, aHandle ));
+
+ aOutputInt = integerReturnBuf();
+ return returnValue;
+ }
+
+
+// ---------------------------------------------------------------------------
+// When noticed the need for 16-bit versions of functions, thought that
+// because asynchronous functions would not work by converting the call
+// from 16-bit to 8-bit in an inline function, we put all the functions into
+// the interface and add implementations here. Also thought that
+// as we have functions to put the 16-bit descriptor through the
+// client-server we use them instead of pushing the 16-bit descriptors in
+// 8-bit descriptors to the other side.
+// Now we can see that this last decision makes up some repitition when
+// it comes to synchronous alloc-functions.
+//
+// Note: If good ideas come up, replace variants of alloc functions that
+// do same things only to different kind of descriptors
+// (8- and 16-bit variants) with possibly only one implementation.
+// ---------------------------------------------------------------------------
+//
+TInt RCatalogsClientServerClientSession::SendSyncAlloc( TInt aFunction,
+ const TDesC8& aInput,
+ HBufC8*& aOutput,
+ TInt aHandle,
+ TInt aLength )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+
+ // Although aOutput should be null, it is deleted to be sure that
+ // no memory is leaked
+ delete aOutput;
+ aOutput = NULL;
+
+ HBufC8* tempReturnBuf( NULL );
+ TInt returnValue = AllocReturnBuf( aLength, tempReturnBuf );
+ if ( returnValue != KErrNone )
+ {
+ return returnValue;
+ }
+
+ TPtr8 tempWritableReturnBuf( NULL, 0 );
+ tempWritableReturnBuf.Set( tempReturnBuf->Des() );
+
+ // Actually these would not need to be in TPckgBuf
+ // when they are not used for returning purposes.
+ TPckgBuf<TInt> function( aFunction );
+ TPckgBuf<TInt> handle( aHandle );
+
+ TInt outcome = SendReceive( ECatalogsExternalAllocMessage,
+ TIpcArgs( &function,
+ &handle,
+ &aInput,
+ &tempWritableReturnBuf ));
+
+ if ( outcome == KCatalogsErrorTooSmallDescriptor )
+ {
+ TInt incompleteMessageHandle = -1;
+ TInt error = RetrieveNewDescLengthAndReAlloc(
+ tempReturnBuf,
+ incompleteMessageHandle );
+ if ( error != KErrNone )
+ {
+ if ( incompleteMessageHandle != -1 )
+ {
+ DeleteIncompleteMessage( incompleteMessageHandle );
+ }
+ aOutput = NULL;
+ delete tempReturnBuf;
+ return error;
+ }
+
+ // to be sure
+ tempWritableReturnBuf.Set( tempReturnBuf->Des() );
+
+ TPckgBuf<TInt> handle( incompleteMessageHandle );
+ TIpcArgs args = TIpcArgs();
+ args.Set( 1, &handle );
+ args.Set( 3, &tempWritableReturnBuf );
+ outcome = SendReceive( ECatalogsCompleteMessage,
+ args );
+
+ }
+
+
+ if ( outcome == KCatalogsErrorTooSmallDescriptor || outcome < 0 )
+ {
+ aOutput = NULL;
+ delete tempReturnBuf;
+ }
+ else
+ {
+ aOutput = tempReturnBuf;
+ }
+ DLTRACEOUT(("outcome: %d, handle: %d", outcome, aHandle));
+ return outcome;
+ }
+
+TInt RCatalogsClientServerClientSession::SendSyncAlloc( TInt aFunction,
+ const TDesC16& aInput,
+ HBufC16*& aOutput,
+ TInt aHandle,
+ TInt aLength )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+
+ // Although aOutput should be null, it is deleted to be sure that
+ // no memory is leaked
+ delete aOutput;
+ aOutput = NULL;
+
+ HBufC16* tempReturnBuf( NULL );
+ TInt returnValue = AllocReturnBuf( aLength, tempReturnBuf );
+ if ( returnValue != KErrNone )
+ {
+ return returnValue;
+ }
+
+ TPtr16 tempWritableReturnBuf( NULL, 0 );
+ tempWritableReturnBuf.Set( tempReturnBuf->Des() );
+
+ // Actually these would not need to be in TPckgBuf
+ // when they are not used for returning purposes.
+ TPckgBuf<TInt> function( aFunction );
+ TPckgBuf<TInt> handle( aHandle );
+
+ TInt outcome = SendReceive( ECatalogsExternalAllocMessage,
+ TIpcArgs( &function,
+ &handle,
+ &aInput,
+ &tempWritableReturnBuf ));
+
+ if ( outcome == KCatalogsErrorTooSmallDescriptor )
+ {
+ TInt incompleteMessageHandle = -1;
+ TInt error = RetrieveNewDescLengthAndReAlloc(
+ tempReturnBuf,
+ incompleteMessageHandle );
+ if ( error != KErrNone )
+ {
+ if ( incompleteMessageHandle != -1 )
+ {
+ DeleteIncompleteMessage( incompleteMessageHandle );
+ }
+ aOutput = NULL;
+ delete tempReturnBuf;
+ return error;
+ }
+
+ // to be sure
+ tempWritableReturnBuf.Set( tempReturnBuf->Des() );
+
+ TPckgBuf<TInt> handle( incompleteMessageHandle );
+ TIpcArgs args = TIpcArgs();
+ args.Set( 1, &handle );
+ args.Set( 3, &tempWritableReturnBuf );
+ outcome = SendReceive( ECatalogsCompleteMessageWide,
+ args );
+
+ }
+
+
+ if ( outcome == KCatalogsErrorTooSmallDescriptor || outcome < 0 )
+ {
+ aOutput = NULL;
+ delete tempReturnBuf;
+ }
+ else
+ {
+ aOutput = tempReturnBuf;
+ }
+
+ DLTRACEOUT(("outcome: %d, handle: %d", outcome, aHandle));
+ return outcome;
+ }
+
+
+
+RFile RCatalogsClientServerClientSession::SendSyncFileOpenL(
+ TInt aFunction,
+ const TDesC8& aInput,
+ TInt aHandle )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+
+ // Actually these would not need to be in TPckgBuf
+ // when they are not used for returning purposes.
+ TPckgBuf<TInt> function( aFunction );
+ TPckgBuf<TInt> handle( aHandle );
+
+ TPckgBuf<TInt> fileHandleBuf;
+
+ DLTRACE(("Sending message to server"));
+
+ TInt fsHandle = SendReceive( ECatalogsExternalMessage,
+ TIpcArgs( &function,
+ &handle,
+ &aInput,
+ &fileHandleBuf ));
+
+ TInt fileHandle = fileHandleBuf();
+ DLTRACE(("AdoptFromServer( %d, %d )", fsHandle, fileHandle ));
+ RFile file;
+ User::LeaveIfError( file.AdoptFromServer( fsHandle, fileHandle ) );
+
+ DLTRACE(("Done, handle: %d", aHandle ));
+
+
+ return file;
+ }
+
+
+
+void RCatalogsClientServerClientSession::SendAsync( TInt aFunction,
+ const TDesC8& aInput,
+ TDes8& aOutput,
+ TInt aHandle,
+ TRequestStatus& aStatus )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+ aStatus = KRequestPending;
+
+ CCatalogsClientServerAsyncTask* task = NULL;
+ TRAPD( error, GetAsyncTaskL( task ) );
+ if ( error != KErrNone )
+ {
+ DLERROR(( "Error getting an async task: %d", error ));
+ // This is called before setActive in client?
+ // Is that a problem?
+ TRequestStatus* status = &aStatus;
+ User::RequestComplete( status, error );
+ return;
+ }
+
+ task->SendAsync( aFunction, aInput, aOutput, aHandle, aStatus );
+ }
+
+
+void RCatalogsClientServerClientSession::SendAsyncAlloc(
+ TInt aFunction,
+ const TDesC8& aInput,
+ HBufC8*& aOutput,
+ TInt aHandle,
+ TRequestStatus& aStatus,
+ TInt aLength )
+ {
+ DLTRACEIN(("Handle: %d", aHandle));
+
+ // Although aOutput should be null, it is deleted to be sure that
+ // no memory is leaked
+ delete aOutput;
+ aOutput = NULL;
+
+ aStatus = KRequestPending;
+
+ CCatalogsClientServerAsyncTask* task = NULL;
+ TRAPD( error, GetAsyncTaskL( task ) );
+ if ( error != KErrNone )
+ {
+ // This is called before setActive in client?
+ // Is that a problem?
+ DLERROR(("Error %d occurred when retrieving new async task", error ));
+ TRequestStatus* status = &aStatus;
+ User::RequestComplete( status, error );
+ return;
+ }
+
+ task->SendAsyncAlloc( aFunction,
+ aInput,
+ aOutput,
+ aHandle,
+ aStatus,
+ aLength );
+ DLTRACEOUT((""));
+ }
+
+void RCatalogsClientServerClientSession::AsyncMessageSenderDown(
+ TRequestStatus& aStatus )
+ {
+ // Go through all messages
+ TInt indexer( iTasks.Count() - 1 );
+ while ( indexer > -1 )
+ {
+ // If the message sender's TRequestStatus is the same as the
+ // given TRequestStatus, the async task should complete
+ // the request immediately and continue to wait for the completion
+ // of the server side message. Comparation done by comparing
+ // pointers to the request statuses.
+ if ( &aStatus == iTasks[indexer]->SendersRequestStatus() )
+ {
+ iTasks[indexer]->SenderDown();
+ }
+ --indexer;
+ }
+ // If no tasks were found with given sender and there has
+ // actually been task(s) that should complete request it is possible
+ // that the request has been recently completed but the completion
+ // has not yet been handled by active scheduler (?) and passed to
+ // the sender.
+ }
+
+void RCatalogsClientServerClientSession::GetAsyncTaskL(
+ CCatalogsClientServerAsyncTask*& aTask )
+ {
+ CCatalogsClientServerAsyncTask* requestedTask =
+ CCatalogsClientServerAsyncTask::NewLC( *this );
+
+ iTasks.AppendL( requestedTask );
+ CleanupStack::Pop( requestedTask );
+
+ aTask = requestedTask;
+ }