phoneclientserver/phoneserver/Src/Messenger/CPhSrvMessengerRequestManager.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:15:03 +0100
branchRCL_3
changeset 20 987c9837762f
parent 19 7d48bed6ce0c
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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.
                        delete iDefaultSizeBuffer;
                        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