phoneclientserver/phoneserver/Src/Messenger/CPhSrvMessengerRequestManager.cpp
changeset 0 ff3b6d0fd310
child 3 a4a774cb6ea7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phoneclientserver/phoneserver/Src/Messenger/CPhSrvMessengerRequestManager.cpp	Tue Feb 02 01:11:09 2010 +0200
@@ -0,0 +1,671 @@
+/*
+* Copyright (c) 2004 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:  Messenger Request Manager.
+*                The stub version of this file can be found from file
+*                CPhSrvMessengerRequestManagerStub.cpp
+*
+*/
+
+
+
+// INCLUDES
+#include "CPhSrvMessengerRequestManager.h"
+#include "CPhSrvMessengerObject.h"
+#include "CPhSrvSubSessionBase.h"
+#include "PhSrvUtils.h"
+#include "PhSrvMessengerTypes.h"
+#include "PhSrvDebugInfo.h"
+
+
+// CONSTANTS
+
+// The default size of the Messenger object storage.
+const TInt KPhSrvMessengerObjectGranularity = 4;
+
+// The size of the Sent message's storage.
+const TInt KPhSrvMessengerPendingSendRequestGranularity 
+    = KPhSrvMessengerObjectGranularity;
+
+
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::CPhSrvMessengerRequestManager
+// 
+// Constructor.
+// -----------------------------------------------------------------------------
+//
+CPhSrvMessengerRequestManager::CPhSrvMessengerRequestManager( 
+    CPhSrvServer& aServer )
+:   iServer( aServer ),
+    iSentDataIdGenerator( 1 ), // Is never 0.
+    iSendProcessOngoing( EFalse )
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::~CPhSrvMessengerRequestManager
+// 
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CPhSrvMessengerRequestManager::~CPhSrvMessengerRequestManager()
+    {
+    delete iDefaultSizeBuffer;
+
+    RMessengerArray* array = SendChain();
+    if ( array )
+        {
+        // Objects not deleted, because they are not owned.
+        array->Reset();
+        array->Close();
+        delete array;
+        }
+
+    array = MessengerArray();
+    if ( array )
+        {
+        array->ResetAndDestroy();
+        array->Close();
+
+        delete array;
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::ConstructL
+// 
+// Complete construction.
+// -----------------------------------------------------------------------------
+//
+void CPhSrvMessengerRequestManager::ConstructL()
+    {
+    iDefaultSizeBuffer = HBufC8::NewMaxL( KPhCltDefMesSize );
+
+    // Space for messenger objects (clients)
+    iMessengerObjects = new ( ELeave ) RPointerArray< 
+        CPhSrvMessengerObject >( KPhSrvMessengerObjectGranularity );
+
+    // Space for the Send queue.
+    iSendChain = new ( ELeave ) RPointerArray< CPhSrvMessengerObject >( 
+        KPhSrvMessengerPendingSendRequestGranularity );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::NegotiatorRequest
+// 
+// Initiate a messenger request - called by the external messenger interface.
+// -----------------------------------------------------------------------------
+//
+void CPhSrvMessengerRequestManager::NegotiatorRequest( 
+    CPhSrvSubSessionBase& aSubSession,
+    const TPhCltMessengerParameters& aParameters,
+    const RMessage2& aMessage )
+    {
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequest START" );   // debug print
+
+    // Panic if this is not the only request from this subsession.
+    if ( RequestAlreadyExists( 
+             aSubSession, 
+             aParameters,
+             aMessage ) )
+        {
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequest PANIC" );   // debug print
+
+        // First delete all data related to this object.
+        NegotiatorRequestDelete( aSubSession );
+
+        PhoneServerUtils::PanicClient( 
+            EPhoneServerPanicTooManyRequestsOngoing,
+            aMessage );
+        }
+    else
+        {
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequest HANDLE" );   // debug print
+
+        // Request was set successfully, so handle it.
+        TPhCltMessengerCommand command = aParameters.iMessengerCommand;
+
+        // Update the messenger chain.
+        UpdateMessengerChain( iRequestObject, command );
+
+        // Clear the request object.
+        iRequestObject = NULL;
+
+        // Complete Skip request.
+        if ( command == EPhCltMesCommandSkip )
+            {
+            aMessage.Complete( KErrNone );
+            }
+        }
+
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequest END" );   // debug print
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::NegotiatorRequestCancel
+// 
+// Cancel a messenger request handling.
+// -----------------------------------------------------------------------------
+//
+void CPhSrvMessengerRequestManager::NegotiatorRequestCancel( 
+    CPhSrvSubSessionBase& aSubSession,
+    const TPhCltMessengerCommand aRequestType )
+    {
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequestCancel START" );   // debug print
+
+    RMessengerArray* messengerObjects = MessengerArray();
+
+    if ( aRequestType == EPhCltMesCommandSend ||
+         aRequestType == EPhCltMesCommandReceive )
+        {
+        // Obtain the subsession's handle
+        const TInt handle = aSubSession.SubSessionUniqueHandle();
+
+        // Now look for any object that match.
+        const TInt count = messengerObjects->Count();
+        for( TInt i = 0; i < count; i++ )
+            {
+            CPhSrvMessengerObject* entry = ( *messengerObjects )[i];
+            if ( entry->SubSessionHandle() == handle )
+                {
+                // Found matching entry, so cancel it's request.
+                entry->InformOfMessengerRequest( KErrCancel, aRequestType );
+
+
+                TPhCltMessengerCommand request = aRequestType;
+                if ( aRequestType == EPhCltMesCommandSend )
+                    {
+                    // Send request is canceled.
+                    request = EPhCltMesCommandCancelSend;
+                    }
+                else
+                    {
+                    // Receive request is canceled.
+                    request = EPhCltMesCommandCancelReceive;
+                    }
+
+                // Update the messenger chain.
+                UpdateMessengerChain( entry, request );
+                }
+            }
+        }
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequestCancel STOP" );   // debug print
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::NegotiatorRequestConstructL
+// 
+// Reserve all space needed for the subsession given as parameter.
+// -----------------------------------------------------------------------------
+//
+void CPhSrvMessengerRequestManager::NegotiatorRequestConstructL( 
+    CPhSrvSubSessionBase& aSubSession,
+    const TPhCltMessengerParameters& aParameters,
+    const RMessage2& aMessage )
+    {
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequestConstructL START" ); // debug print
+
+    // Create pending request
+    CPhSrvMessengerObject* object = CPhSrvMessengerObject::NewLC(
+        aSubSession,
+        aParameters );
+
+    RMessengerArray* sendArray = SendChain();
+    RMessengerArray* messengerObjects = MessengerArray();
+
+    /////////////////////////////////////////////////////////////////
+    // First try that there is enough space in send array.
+    /////////////////////////////////////////////////////////////////
+    const CPhSrvMessengerObject* entry = NULL;
+    TInt err = KErrNone;
+    // The number of existing messenger objects + the new one.
+    const TInt count = ( messengerObjects->Count() + 1 );
+
+    TInt i = 0;
+    for ( i = 0; ( i < count ) && ( err == KErrNone ); i++ )
+        {
+        // If Append failed, there is not enough memory and err != KErrNone.
+        err = sendArray->Append( entry );
+        }
+
+    // Remove now the added objects -> Buffer remains reserved for them.
+    const TInt sendChainCount = ( sendArray->Count() - 1 );
+    for( i = sendChainCount; i >= 0; i-- )
+        {
+        if( ( * sendArray )[i] == NULL )
+            {
+            // This object was added, so remove it.
+            sendArray->Remove( i );
+            }
+        }
+
+    // Leave if addition to send chain were not successful.
+    User::LeaveIfError( err );
+
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequestConstructL MIDDLE" ); // debug print
+
+    /////////////////////////////////////////////////////////////////
+    // There was enough space in send array, so next try to append the 
+    // object to the object array.
+    /////////////////////////////////////////////////////////////////
+    User::LeaveIfError( 
+        messengerObjects->Append( object ) );
+    CleanupStack::Pop( object );
+
+    aMessage.Complete( KErrNone );
+
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequestConstructL STOP" );  // debug print
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::NegotiatorRequestDelete
+// 
+// Delete all space reserved for the subsession given as parameter.
+// -----------------------------------------------------------------------------
+//
+void CPhSrvMessengerRequestManager::NegotiatorRequestDelete( 
+    CPhSrvSubSessionBase& aSubSession )
+    {
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequestDelete START" );   // debug print
+
+    // Obtain the subsessions handle
+    const TInt handle = aSubSession.SubSessionUniqueHandle();
+
+    RMessengerArray* messengerObjects = MessengerArray();
+
+    // Now look for any object that match.
+    TInt count = messengerObjects->Count() - 1;
+    for( TInt i = count; i >= 0; i-- )
+        {
+        CPhSrvMessengerObject* entry = ( *messengerObjects )[i];
+        if ( entry->SubSessionHandle() == handle )
+            {
+            // Found matching entry, so cancel it and clean up.
+
+            // This object is not in handled objects anymore.
+            // This means also that objects receive is also canceled.
+            messengerObjects->Remove( i );
+
+            // Update the messenger chain, cancel Send.
+            UpdateMessengerChain( entry, EPhCltMesCommandCancelSend );
+
+            // Send and receive were canceled, so this entry can be destroyed.
+            delete entry;
+            }
+        }
+    _DPRINT( 4, "PhSrv.MRM.NegotiatorRequestDelete STOP" );   // debug print
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::UpdateMessengerChain
+// 
+// Update the request objects.
+// -----------------------------------------------------------------------------
+//
+void CPhSrvMessengerRequestManager::UpdateMessengerChain(
+    CPhSrvMessengerObject* aEntry,
+    TPhCltMessengerCommand aCommand )
+    {
+    _DPRINT( 4, "PhSrv.MRM.Negotiator.Update START" );   // debug print
+
+    TInt err = KErrNone;
+    RMessengerArray* sendArray = SendChain();
+
+
+    if ( aEntry )
+        {
+        switch ( aCommand )
+            {
+            case EPhCltMesCommandSend:
+                {
+                // If this is new request, append it to send queue.
+                if( sendArray->Find( aEntry ) == KErrNotFound )
+                    {
+                    err = sendArray->Append( aEntry );
+                    if ( err )
+                        {
+                        // Should never happen because of space pre-reservation
+                        // in construction phase. However, recover.
+
+                        // If Append did not succeed, inform Sender of failure.
+                        aEntry->InformOfMessengerRequest( 
+                            err,
+                            EPhCltMesCommandSend );
+                        }
+                    }
+
+                // If Append was not performed or if it was successful.
+                if ( !err )
+                    {
+                    // Handle all Send requests that exist.
+                    HandleAllSendRequests( aEntry, sendArray );
+                    }
+                break;
+                }
+            case EPhCltMesCommandReceive:
+            case EPhCltMesCommandSkip:
+            case EPhCltMesCommandCancelReceive:
+                {
+                // Handle all Send requests that exist.
+                HandleAllSendRequests( NULL, sendArray );
+                break;
+                }
+
+            case EPhCltMesCommandCancelSend:
+                {
+                // Remove this Send object from chain.
+                // Pending Receive requests not completed.
+                TInt location = sendArray->Find( aEntry );
+                if ( location >= 0 )
+                    {
+                    // If this is the first object in Send chain, then
+                    // Send request processing is canceled.
+                    if( aEntry == ( *sendArray )[0] )
+                        {
+                        iSendProcessOngoing = EFalse;
+                        }
+                    sendArray->Remove( location );
+                    }
+
+                // Handle all other Send requests that exist.
+                HandleAllSendRequests( NULL, sendArray );
+                break;
+                }
+
+            default:
+                // Should never happen!
+                break;
+            }
+        }
+    _DPRINT( 4, "PhSrv.MRM.Negotiator.Update STOP" );   // debug print
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::HandleAllSendRequests
+// 
+// 
+// -----------------------------------------------------------------------------
+//
+void CPhSrvMessengerRequestManager::HandleAllSendRequests(
+    CPhSrvMessengerObject* aEntry,
+    RMessengerArray* aSendArray )
+    {
+    CPhSrvMessengerObject* entry = aEntry;
+
+    // If aEntry is NULL, try to set it as valid object.
+    if ( !entry )
+        {
+        if ( aSendArray->Count() )
+            {
+            entry = ( *aSendArray )[0]; // Take the first object in send chain.
+            }
+        }
+
+    // Handle all Send requests that exists.
+    while ( HandleSendRequest( entry, aSendArray ) )
+        {
+        entry = NULL;
+        if ( aSendArray->Count() )
+            {
+            entry = ( *aSendArray )[0]; // Take the first object in send chain.
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::HandleSendRequest
+// 
+// 
+// -----------------------------------------------------------------------------
+//
+TBool CPhSrvMessengerRequestManager::HandleSendRequest( 
+    CPhSrvMessengerObject* aEntry,
+    RMessengerArray* aSendArray )
+    {
+    TBool ret = EFalse;
+    RMessengerArray* messengerObjects = MessengerArray();
+
+
+    // Handling is done only if there is Send request and 
+    // aEntry is valid object.
+    if( aSendArray->Count() && aEntry )
+        {
+        if ( aEntry == ( *aSendArray )[0] )
+            {
+            // This was the first Send operation so complete Receives.
+
+            // Some pre-work needs to be done if this Send has not been 
+            // handled before.
+            if( !iSendProcessOngoing )
+                {
+                // Now this Send request process is ongoing.
+                iSendProcessOngoing = ETrue;
+
+                const TInt sentDataLength = aEntry->GetSendDataLength();
+
+                if ( sentDataLength > 
+                     iDefaultSizeBuffer->Des().MaxLength() )
+                    {
+                    // The sent data is longer than the default buffer.
+                    // We need to try reserve bigger buffer. If this does not
+                    // succeed, then only the current size buffer is used in 
+                    // sending.
+
+                    HBufC8* variableSizeBuffer = NULL;
+                    variableSizeBuffer = HBufC8::New( sentDataLength );
+                    if ( variableSizeBuffer != NULL )
+                        {
+                        // Reservation was successful, so use reserved buffer
+                        // as a new default buffer. 
+                        // But first delete the old buffer.
+                        if( iDefaultSizeBuffer )
+                            {
+                            delete iDefaultSizeBuffer;
+                            iDefaultSizeBuffer = NULL;
+                            }
+                        iDefaultSizeBuffer = variableSizeBuffer;
+                        }
+                    }
+                // Read the sent message.
+                TPtr8 ptr = iDefaultSizeBuffer->Des();
+                aEntry->GetSendData( ptr );
+                }
+
+
+            const TDesC8& sendData = *iDefaultSizeBuffer;
+            const TUid& senderUid = aEntry->GetUid();
+            const TUint sentDataId = aEntry->SentDataId();
+
+            TBool completeSend = ETrue;
+            TInt interested = 0;
+
+            TInt count = messengerObjects->Count();
+
+            ////////////////////////////////////////////////////////
+            // Check that all the objects are ready to receive.
+            ////////////////////////////////////////////////////////
+            for( TInt i = 0; i < count; i++ )
+                {
+                CPhSrvMessengerObject* entry = ( *messengerObjects )[i];
+
+                // Check only other objects.
+                if ( aEntry->SubSessionHandle() != entry->SubSessionHandle() )
+                    {
+                    // We need to care only of those objects that want to
+                    // listen messages same type as the sent was.
+                    if( senderUid == entry->GetUid() )
+                        {
+                        // This object wants to receive this sent message.
+                        interested++;
+
+                        if ( !entry->IsReadyToReceive( sendData, sentDataId ) )
+                            {
+                            // The object was not ready to receive, so Send can 
+                            // not be completed yet.
+                            completeSend = EFalse;
+                            }
+                        }
+                    }
+                }
+
+
+            ////////////////////////////////////////////////////////
+            // If all objects were ready to receive, complete them.
+            // If there were no objects interested of the sent message,
+            // do nothing.
+            ////////////////////////////////////////////////////////
+            if ( completeSend && interested )
+                {
+                for( TInt i = 0; i < count; i++ )
+                    {
+                    CPhSrvMessengerObject* entry = ( *messengerObjects )[i];
+
+                    // Complete only other's Receive requests.
+                    if ( aEntry->SubSessionHandle() != 
+                         entry->SubSessionHandle() )
+                        {
+                        // We complete only those object's receives that have
+                        // the same category UID as the sent was.
+                        if( senderUid == entry->GetUid() )
+                            {
+                            TInt err = entry->CompleteReceive( 
+                                sendData,
+                                sentDataId );
+                            if( err )
+                                {
+                                // This should never fail because pre-check was
+                                // successful. However, you can try to recover.
+                                }
+                            }
+                        }
+                    }
+                // All receives were compeled, so complete Send.
+                aEntry->InformOfMessengerRequest( 
+                    KErrNone,
+                    EPhCltMesCommandSend );
+                // Remove the object whose Send was handled from chain.
+                aSendArray->Remove( 0 );
+
+                // The send process was completed.
+                iSendProcessOngoing = EFalse;
+
+                // Send was fully handled.
+                ret = ETrue;
+                }
+            }
+        }
+    return ret;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::RequestAlreadyExists
+// 
+// Check whether there already is request(s) for the subsession given as 
+// parameter. If not, then sets it active.
+// -----------------------------------------------------------------------------
+//
+TBool CPhSrvMessengerRequestManager::RequestAlreadyExists( 
+    const CPhSrvSubSessionBase& aSubSession,
+    const TPhCltMessengerParameters& aParameters,
+    const RMessage2& aMessage )
+    {
+    TBool isThereRequest = EFalse;
+    const TPhCltMessengerCommand command = aParameters.iMessengerCommand;
+
+    // Check is only done for Send and Receive and Skip.
+    if ( command == EPhCltMesCommandSend ||
+         command == EPhCltMesCommandReceive ||
+         command == EPhCltMesCommandSkip )
+        {
+        // Obtain the subsessions handle
+        const TInt handle = aSubSession.SubSessionUniqueHandle();
+
+        RMessengerArray* messengerObjects = MessengerArray();
+
+        // Look for any pending requests that match the handle.
+        TInt i = 0;
+        for( i = 0; i < messengerObjects->Count(); i++ )
+            {
+            CPhSrvMessengerObject* entry = ( *messengerObjects )[i];
+            if ( entry->SubSessionHandle() == handle )
+                {
+                isThereRequest = entry->IsRequestActive( command );
+                if ( !isThereRequest )
+                    {
+                    TUint sentDataId = 0;
+                    if( command == EPhCltMesCommandSend )
+                        {
+                        // This was sent command, so set ID for it.
+                        sentDataId = iSentDataIdGenerator;
+                        // New Id for next sent message, must never be 0!
+                        iSentDataIdGenerator++;
+                        if( !iSentDataIdGenerator )
+                            {
+                            // Value was 0, so set to 1.
+                            iSentDataIdGenerator++;
+                            }
+                        }
+                    // Request was not active, so set it active.
+                    entry->SetActive( aParameters, aMessage, sentDataId );
+                    }
+
+                // Set the object who initiated this request.
+                iRequestObject = entry;
+                break;
+                }
+            }
+        }
+    return isThereRequest;
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::MessengerArray
+// 
+// 
+// -----------------------------------------------------------------------------
+//
+RMessengerArray* CPhSrvMessengerRequestManager::MessengerArray()
+    {
+    return iMessengerObjects;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPhSrvMessengerRequestManager::SendChain
+// 
+// 
+// -----------------------------------------------------------------------------
+//
+RMessengerArray* CPhSrvMessengerRequestManager::SendChain()
+    {
+    return iSendChain;
+    }
+
+
+// End of File