diff -r 000000000000 -r ba25891c3a9e ncdengine/engine/src/catalogsclientserverserversession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ncdengine/engine/src/catalogsclientserverserversession.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,546 @@ +/* +* 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 CCatalogsClientServerServerSession +* +*/ + + +#include + +#include "catalogsclientserverserversession.h" +#include "catalogsserverdefines.h" +#include "catalogscommunicable.h" +#include "catalogsbasemessageimpl.h" +#include "catalogsincompletemessage.h" +#include "catalogscontextimpl.h" +#include "catalogsdebug.h" + + +// ======== LOCAL FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// Cleanupfunction for cleanupitem usage. Closes CObject based +// object as many times as needed to destroy it when removed +// from cleanupstack. +// --------------------------------------------------------------------------- +// +void CCatalogsClientServerServerSession::CleanupCObjectBasedClass( TAny* aCObject ) + { + CObject* convertedCObject = ( static_cast< CObject* > ( aCObject ) ); + TInt accessCount = convertedCObject->AccessCount(); + while ( accessCount > 0 ) + { + convertedCObject->Close(); + --accessCount; + } + // Now that last reference is closed, aCObject is destroyed + } + + +// ======== MEMBER FUNCTIONS ======== + +CCatalogsClientServerServerSession* CCatalogsClientServerServerSession::NewL( + RThread& aClient, + CCatalogsClientServerServer& aServer ) + { + CCatalogsClientServerServerSession* self = + CCatalogsClientServerServerSession::NewLC( aClient, aServer ); + CleanupStack::Pop(self) ; + return self ; + } + +CCatalogsClientServerServerSession* CCatalogsClientServerServerSession:: + NewLC( RThread& aClient, CCatalogsClientServerServer& aServer ) + { + CCatalogsClientServerServerSession* self = + new (ELeave) CCatalogsClientServerServerSession( aClient, aServer, + aServer.NewInstanceId() ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +CCatalogsClientServerServerSession::CCatalogsClientServerServerSession( + RThread& /*aClient*/, + CCatalogsClientServerServer& aServer, + TInt aInstanceId ) : + CSession2(), + iClientSideDownAnnounced( ENotInformed ), + iServer( aServer ), + iInstanceId( aInstanceId ) + { + } + +CCatalogsClientServerServerSession::~CCatalogsClientServerServerSession() + { + DLTRACEIN(("")); + ClientSideSessionDown(); + DLTRACE(("Deleting context")); + delete iContext; + iServer.DecrementSessions(); + DLTRACEOUT(("")); + } + +void CCatalogsClientServerServerSession::ConstructL() + { + iServer.IncrementSessions(); + iMessageHandlers = CObjectIx::NewL(); + iIncompleteMessageContainer = iServer.NewContainerL(); + iIncompleteMessages = CObjectIx::NewL(); + + } + +void CCatalogsClientServerServerSession::ClientSideSessionDown() + { + DLTRACEIN(("")); + if ( iClientSideDownAnnounced == ENotInformed ) + { + DLTRACE(("Delete incomplete messages")); + // Incomplete messages act as receivers of messages as well + // as nodes etc. + delete iIncompleteMessages; + iIncompleteMessages = NULL; + + // In examples, container is simply deleted, but here + // this ends up making a KERN-EXEC 3. Probably container is + // removed for a second time when the container-index is removed. + if ( iIncompleteMessageContainer != NULL ) + { + DLTRACE(("Remove container")); + iServer.RemoveContainer( iIncompleteMessageContainer ); + DLTRACE(("Container removed")); + } + iIncompleteMessageContainer = NULL; + + + CloseMessageHandlers(); + + DLTRACE(("Handle session removal")); + // Inform possibly interested objects of session removal + // so they know that this session does not exist anymore + iServer.HandleSessionRemoval( *this ); + + iClientSideDownAnnounced = EInformed; + } + + DLTRACEOUT(("")); + } + + +TInt CCatalogsClientServerServerSession::WriteToLargerDesL( + const TDesC8& aOutputData, + TInt aStatus ) + { + CCatalogsIncompleteMessage* incompleteMessage = + CCatalogsIncompleteMessage::NewL(); + + // NOTICE: Because a CObject-derived object cannot be deleted + // when its reference count is not zero, we use a + // cleanup-item. Another way could be to do it in the + // destructor of the CObject-derived object, but + // it could enable unintended destruction of the object.? + TCleanupItem cleanupCObjectInfo( CleanupCObjectBasedClass, + incompleteMessage ); + CleanupStack::PushL( cleanupCObjectInfo ); + + incompleteMessage->SetMessageL( aOutputData, aStatus ); + iIncompleteMessageContainer->AddL( incompleteMessage ); + TInt handle = iIncompleteMessages->AddL( incompleteMessage ); + + CleanupStack::Pop( incompleteMessage ); + return handle; + } + +TInt CCatalogsClientServerServerSession::WriteToLargerDesL( + const TDesC16& aOutputData, + TInt aStatus ) + { + CCatalogsIncompleteMessage* incompleteMessage = + CCatalogsIncompleteMessage::NewL(); + + // NOTICE: Because a CObject-derived object cannot be deleted + // when its reference count is not zero, we use a + // cleanup-item. Another way could be to do it in the + // destructor of the CObject-derived object, but + // it could enable unintended destruction of the object.? + TCleanupItem cleanupCObjectInfo( CleanupCObjectBasedClass, + incompleteMessage ); + CleanupStack::PushL( cleanupCObjectInfo ); + + incompleteMessage->SetMessageL( aOutputData, aStatus ); + iIncompleteMessageContainer->AddL( incompleteMessage ); + TInt handle = iIncompleteMessages->AddL( incompleteMessage ); + + CleanupStack::Pop( incompleteMessage ); + return handle; + } + +void CCatalogsClientServerServerSession::RemoveIncompleteMessage( TInt aHandle ) + { + iIncompleteMessages->Remove( aHandle ); + } + +void CCatalogsClientServerServerSession::ServiceL( const RMessage2& aMessage ) + { + DLTRACEIN(("")); + + // If ServiceL leaves, the framework calls ServiceError which by default + // completes the message with the leave code if it has not been completed + // yet + HandleMessageL( aMessage ); + } + +TInt CCatalogsClientServerServerSession::AddObjectL( + CObject* aObject ) + { + iServer.AddObjectToContainerL( aObject ); + TInt handle( iMessageHandlers->AddL( aObject ) ); + // Because add to the ix does not call Open() of the CObject, + // we have to do it ourselves + User::LeaveIfError( aObject->Open() ); + return handle; + } + +void CCatalogsClientServerServerSession::RemoveObject( TInt aHandle ) + { + // This closes the CObject once. + iMessageHandlers->Remove( aHandle ); + } + +MCatalogsContext& CCatalogsClientServerServerSession::Context() + { + return *iContext; + } + + +const MCatalogsContext* CCatalogsClientServerServerSession::ContextPtr() const + { + return iContext; + } + + +void CCatalogsClientServerServerSession::HandleMessageL( + const RMessage2& aMessage ) + { + DLTRACEIN(("Function: %X", aMessage.Function() )); + + // NOTICE: If aMessage has to be stored and used later + // then copy it and use the copy instead. + + if ( iClientSideDownAnnounced == EInformed ) + { + // Do not communicate to client anymore + // client-side session is going down + return; + } + else if( ( aMessage.Function() != ECatalogsCreateContext ) + && ( iContext == NULL ) ) + { + DLERROR(( "Completing message with KErrNotReady" )); + aMessage.Complete( KErrNotReady ); + } + + + if( aMessage.Function() == ECatalogsExternalMessage + || aMessage.Function() == ECatalogsExternalAllocMessage ) + { + HandleExternalMessageL( aMessage ); + } + else + { + HandleInternalMessageL( aMessage ); + } + DLTRACEOUT(("")); + } + +void CCatalogsClientServerServerSession::HandleExternalMessageL( + const RMessage2& aMessage ) + { + DLTRACEIN(("")); + TPckgBuf handle; + aMessage.ReadL( 1, handle ); + + + CCatalogsCommunicable* receiver = ReceiverFromHandle( handle() ); + + DLTRACE(("Receiver for message: %X", receiver )); + + if( !receiver ) + { + PanicClient( aMessage, EBadHandle ); + return; + } + + + CCatalogsBaseMessageImpl* baseMessage = + CCatalogsBaseMessageImpl::NewLC( aMessage, + *this, + handle() ); + TPckgBuf funcNumber; + aMessage.ReadL( 0, funcNumber ); + + CleanupStack::Pop( baseMessage ); + + DLTRACE(("Passing message")); + + // Now the message is already passed to the receiver + // and it is its duty to use it to inform of possible + // error situations + // -> Nothing is done here + receiver->ReceiveMessage( baseMessage, funcNumber() ); + + DLTRACEOUT(("Message passed")); + } + +void CCatalogsClientServerServerSession::HandleInternalMessageL( + const RMessage2& aMessage ) + { + DLTRACEIN(("")); + switch( aMessage.Function() ) + { + case ECatalogsCompleteMessage: + { + DLTRACE(("ECatalogsCompleteMessage")); + TPckgBuf handle; + aMessage.ReadL( 1, handle ); + + CCatalogsIncompleteMessage* incompleteMessage = + IncompleteMessageFromHandle( handle() ); + if( !incompleteMessage ) + { + PanicClient( aMessage, EBadHandle ); + return; + } + + const TDesC8& message = incompleteMessage->Message(); + TInt returnValue = incompleteMessage->ReturnValue(); + + DLINFO(( "Writing message" )); + TRAPD( error, aMessage.WriteL( 3, message ) ); + if ( error != KErrNone ) + { + RemoveIncompleteMessage( handle() ); + User::Leave( error ); + } + + DLINFO(( "Completing message with %d", returnValue )); + aMessage.Complete( returnValue ); + + RemoveIncompleteMessage( handle() ); + break; + } + + + case ECatalogsCompleteMessageWide: + { + DLTRACE(("ECatalogsCompleteMessageWide")); + TPckgBuf handle; + aMessage.ReadL( 1, handle ); + + CCatalogsIncompleteMessage* incompleteMessage = + IncompleteMessageFromHandle( handle() ); + if( !incompleteMessage ) + { + PanicClient( aMessage, EBadHandle ); + return; + } + + const TDesC16& message = incompleteMessage->MessageWide(); + TInt returnValue = incompleteMessage->ReturnValue(); + + DLINFO(( "Writing message" )); + TRAPD( error, aMessage.WriteL( 3, message ) ); + if ( error != KErrNone ) + { + RemoveIncompleteMessage( handle() ); + User::Leave( error ); + } + + DLINFO(( "Completing message with %d", returnValue )); + aMessage.Complete( returnValue ); + RemoveIncompleteMessage( handle() ); + break; + } + + case ECatalogsRemoveIncompleteMessage: + { + DLTRACE(("ECatalogsRemoveIncompleteMessage")); + TPckgBuf handle; + aMessage.ReadL( 1, handle ); + RemoveIncompleteMessage( handle() ); + DLINFO(( "Completing message with KErrNone" )); + aMessage.Complete( KErrNone ); + + break; + } + case ECatalogsClientSideDown: + { + DLTRACE(("ECatalogsClientSideDown")); + ClientSideSessionDown(); + DLINFO(( "Completing message with KErrNone" )); + aMessage.Complete( KErrNone ); + break; + } + + case ECatalogsCreateProvider: + { + DLTRACE(("Create Provider")); + + CreateProviderL( aMessage ); + DLTRACE(("Create Provider done")); + break; + } + + case ECatalogsCreateContext: + { + DLTRACE(("ECatalogsCreateContext")); + CreateContextL( aMessage ); + break; + } + + default: + { + } + } + } + +void CCatalogsClientServerServerSession::CreateProviderL( + const RMessage2& aMessage ) + { + DLTRACEIN(("")); + + TInt providerUid = aMessage.Int0(); + TUint32 providerOptions = aMessage.Int2(); + + // We have to have a integer which contains the handle to be + // able to write it into client side later. + TInt tempHandle( 0 ); + + TRAPD( outcome, + iServer.CreateProviderL( + *this, providerUid, tempHandle, providerOptions ) ); + + // KErrNone and positive codes are a success. Cache cleaning + // can cause positive leaves + if ( outcome >= KErrNone ) + { + DLTRACE(("Writing the provider handle to the message")); + TPckgBuf handleBuf( tempHandle ); + + TRAPD( err, aMessage.WriteL( 1, handleBuf ) ); + if ( err != KErrNone ) + { + DLTRACE(("Couldn't pass the handle back")); + // If we can't pass the handle back, there is no use + // to try to continue normally. + RemoveObject( tempHandle ); + outcome = err; + } + } + DLTRACE(("Completing message with: %d", outcome )); + aMessage.Complete( outcome ); + } + + +void CCatalogsClientServerServerSession::CreateContextL( + const RMessage2& aMessage ) + { + DLTRACEIN(("")); + if ( iContext != NULL ) + { + DLERROR(( "Completing message with KErrAlreadyExists" )); + aMessage.Complete( KErrAlreadyExists ); + return; + } + + TInt familyIdTint = aMessage.Int0(); + TUid familyIdUid = TUid::Uid( familyIdTint ); + TSecureId secureId = aMessage.SecureId(); + + iContext = CCatalogsContextImpl::NewL( familyIdUid, secureId, iInstanceId ); + + // cancel shutdown operations for this family + iServer.OperateShutdownOperations( Context(), EFalse ); + + DLINFO(( "Completing message with KErrNone" )); + aMessage.Complete( KErrNone ); + DLTRACEOUT(("")); + } + +void CCatalogsClientServerServerSession::PanicClient( + const RMessage2& aMessage, TInt aPanic ) const + { + DLTRACEIN(("")); + // NOTICE: KTxtCatalogsSession should not exceed 16 characters. + // If it does, it will result in USER 23. So it seems + // that RMEssage2::Panic does not truncate the characters + // that exceed those 16 characters. + _LIT( KTxtCatalogsSession,"CCatalogsSession" ); + aMessage.Panic( KTxtCatalogsSession, aPanic ); + } + +CCatalogsCommunicable* + CCatalogsClientServerServerSession::ReceiverFromHandle( TInt aHandle ) + { + DLTRACEIN(("")); + if ( iMessageHandlers == NULL ) + { + return NULL; + } + // Normal situation + CCatalogsCommunicable* handler = + static_cast( iMessageHandlers->At( aHandle ) ); + DLTRACEOUT(("")); + return handler; + } + +CCatalogsIncompleteMessage* + CCatalogsClientServerServerSession::IncompleteMessageFromHandle( TInt aHandle ) + { + DLTRACEIN(("")); + if ( iIncompleteMessages == NULL ) + { + return NULL; + } + + // Normal situation + CCatalogsIncompleteMessage* message = + static_cast( + iIncompleteMessages->At( aHandle ) ); + DLTRACEOUT(("")); + return message; + } + +void CCatalogsClientServerServerSession::CloseMessageHandlers() + { + DLTRACEIN(("")); + TInt communicableCount( iMessageHandlers->Count() ); + for ( TInt index = 0; index < communicableCount; ++index ) + { + CCatalogsCommunicable* handler = + static_cast( ( *iMessageHandlers )[index] ); + // If handlers have been removed, iMessageHandlers seem to contain + // null pointers in place of those removed handlers + if ( handler != NULL ) + { + handler->CounterPartLost( *this ); + } + } + + // Deletion closes all referenced objects once + delete iMessageHandlers; + iMessageHandlers = NULL; + + DLTRACEOUT(("")); + }