connectionmonitoring/connmon/connectionmonitor/src/CPlugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:33:49 +0200
changeset 2 086aae6fc07e
parent 0 5a93021fdf25
permissions -rw-r--r--
Revision: 201001 Kit: 201003

/*
* Copyright (c) 2003-2007 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:  Plug-in object subsession.
*
*/

#include "ConnMonServ.h"
#include "ConnMonIAP.h"
#include "CEventQueue.h"
#include "CPlugin.h"
#include "log.h"

// ============================ MEMBER FUNCTIONS ===============================

// Constructor
TAttributeRequest::TAttributeRequest(
        TUint aType,
        TUint aAttribute,
        TUint aData )
        :
        iType( aType ),
        iAttribute( aAttribute ),
        iData( aData )
    {
    }

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CPlugin::CPlugin
// -----------------------------------------------------------------------------
//
CPlugin::CPlugin()
    {
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CPlugin::~CPlugin()
    {
    // Complete any outstanding plug-in request
    CancelGetQuery();

    // Close the attributes array
    iAttributesSupported.Close();

    // Complete all outstanding client requests
    TInt count = iClientRequests.Count();

    for ( TInt i = 0; i < count; i++ )
        {
        const TClientRequest* req = &( iClientRequests[i] );

        // Complete only asynchronous client requests
        if ( req->iType == EReqGetIntAttribute ||
             req->iType == EReqGetUintAttribute ||
             req->iType == EReqGetBoolAttribute ||
             req->iType == EReqGetStringAttribute ||
             req->iType == EReqGetPckgAttribute )
            {
            req->iMessage.Complete( KErrCancel );
            }
        }

    iClientRequests.Close();

    iSession = 0;

    LOGIT1("SERVER: Plugin destroyed, id <%d>", iPluginId )
    }

// -----------------------------------------------------------------------------
// CPlugin::NewL
// -----------------------------------------------------------------------------
//
CPlugin* CPlugin::NewL( CConnMonSession* aSession, const TUint aPluginId )
    {
    CPlugin* self = new ( ELeave ) CPlugin;

    CleanupStack::PushL( self );
    self->ConstructL( aSession, aPluginId );
    CleanupStack::Pop( self );

    return self;
    }

// -----------------------------------------------------------------------------
// CPlugin::ConstructL
// -----------------------------------------------------------------------------
//
void CPlugin::ConstructL( CConnMonSession* aSession, const TUint aPluginId )
    {
    TName name;

    name.Format( KPluginName, this );
    SetNameL( &name );

    iSession = aSession;
    iPluginId = aPluginId;
    }

// -----------------------------------------------------------------------------
// CPlugin::RegisterAttribute
// -----------------------------------------------------------------------------
//
TInt CPlugin::RegisterAttribute( const TUint aAttribute )
    {
    LOGIT2("SERVER: EReqPluginRegisterAttribute, id <%d>, attr <%d>", iPluginId, aAttribute )

    for ( TInt i = 0; i < iAttributesSupported.Count(); i++ )
        {
        if ( iAttributesSupported[i] == aAttribute )
            {
            // Attribute has already been registered
            return ( KErrNone );
            }
        }

    iAttributesSupported.Append( aAttribute );

    // Check if the clients have set 'KBearerAvailabilityThreshold' earlier
    if ( aAttribute == KBearerAvailabilityThreshold )
       {
       TUint th( 0 );

       // Have clients set the threshold earlier
       iSession->iCmServer->CalculateThreshold( 0, EBearerAvailabilityThreshold, th );

       if ( th == 1 )
           {
           // Add the request (set threshold) to the queue (aPending is EFalse)
           const RMessage2 dummy;

           TClientRequest clientReq( EReqInternalSetThreshold, EFalse, dummy );
           iClientRequests.Append( clientReq );
           }
       }

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CPlugin::CancelRegisterAttribute
// -----------------------------------------------------------------------------
//
TInt CPlugin::CancelRegisterAttribute( const TUint aAttribute )
    {
    LOGIT2("SERVER: EReqPluginCancelRegisterAttribute, id <%d>, attr <%d>", iPluginId, aAttribute )

    for ( TInt i = 0; i < iAttributesSupported.Count(); i++ )
        {
        if ( iAttributesSupported[i] == aAttribute )
            {
            // Complete any outstanding client requets
            TInt count = iClientRequests.Count();

            for ( TInt j = 0; j < count; j++ )
                {
                const TClientRequest* req = &( iClientRequests[j] );

                if  ( static_cast< TInt >( aAttribute ) == req->iMessage.Int2( ) )
                    {
                    // Complete only asynchronous client requests
                    if ( req->iType == EReqGetIntAttribute ||
                         req->iType == EReqGetUintAttribute ||
                         req->iType == EReqGetBoolAttribute ||
                         req->iType == EReqGetStringAttribute ||
                         req->iType == EReqGetPckgAttribute )
                        {
                        req->iMessage.Complete( KErrCancel );
                        }
                    iClientRequests.Remove( j );
                    count--;
                    j--;
                    }
                }

            iAttributesSupported.Remove( i );
            return ( KErrNone );
            }
        }

    return KErrNotFound;
    }

// -----------------------------------------------------------------------------
// CPlugin::Event
// -----------------------------------------------------------------------------
//
TInt CPlugin::Event(
        const RMessage2& aMessage,
        TEventInfo& aEventInfo,
        TUint8*& aPtr,
        TInt& aSize ) const
    {
    TUint eventId = aMessage.Int0();

    TUint desLen = aMessage.GetDesLength( 1 );

    // Max allowed data size is 512 bytes
    if ( desLen > KConnMonMaxPluginDataSize )
        {
        return KErrTooBig;
        }

    HBufC8* buf = HBufC8::New( desLen );

    if ( !buf )
        {
        return KErrNoMemory;
        }

    TPtr8 initptr = buf->Des();

    // Read the contents of the client pointer into a TPtr.
    TInt res = aMessage.Read( 1, initptr );

    if ( res != KErrNone )
        {
        delete buf;
        iSession->iCmServer->PanicClient( EBadDescriptor );
        return KErrBadHandle;
        }

    // Create the event to be forwarded to the clients
    aEventInfo.Reset();

    aEventInfo.iEventType = eventId;
    aEventInfo.iConnectionId = iPluginId;

    if ( ( eventId == EConnMonSignalStrengthChange ) && ( desLen == sizeof( TInt ) ) )
        {
        // Signal strength changed event
        aEventInfo.iData = static_cast<TInt>( *initptr.Ptr() );
        }
    else if ( ( eventId == EConnMonBearerAvailabilityChange ) && ( desLen == sizeof( TBool ) ) )
        {
        // Bearer availability changed event
        aEventInfo.iData = static_cast<TBool>( *initptr.Ptr() );
        }
    else if ( ( eventId == EConnMonIapAvailabilityChange ) &&
              ( desLen == sizeof( TConnMonIapInfo ) ) )
        {
        // IAP availability changed event
        TConnMonIapInfo* receivedIapInfo =
            const_cast<TConnMonIapInfo*>(
                reinterpret_cast<const TConnMonIapInfo*>( initptr.Ptr() ) );

        // Event contains only limited info on IAPs (= count + IDs)
        TConnMonIapInfo* eventIaps( NULL );
        eventIaps = new TConnMonIapInfo;

        if ( eventIaps )
            {
            aEventInfo.iData = receivedIapInfo->Count();

            eventIaps->iCount = receivedIapInfo->Count();

            for ( TInt i = 0; i < KConnMonMaxIAPCount && i < receivedIapInfo->Count(); i++ )
                {
                eventIaps->iIap[i].iIapId = receivedIapInfo->iIap[i].iIapId;
                }

            aPtr = reinterpret_cast<TUint8*>( eventIaps );
            aSize = sizeof( TConnMonIapInfo );
            }
        }
    else if ( ( eventId >= EConnMonPluginEventBase ) && ( desLen == sizeof( TUint ) ) )
        {
        // Plugin specific event. Only 32-bit data (desLen is 4 bytes) supported so far
        aEventInfo.iData = static_cast<TUint>( *initptr.Ptr() );
        aEventInfo.iData2 = desLen;
        }
    else
        {
        // Event is not supported
        LOGIT2("SERVER: Plugin sent unsupported event or length of the data was invalid. -> id <%d>, event <%d>", iPluginId, eventId )

        delete buf;
        return KErrNotSupported;
        }

    delete buf;

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CPlugin::Attribute
// -----------------------------------------------------------------------------
//
TInt CPlugin::Attribute( const RMessage2& aMessage )
    {
    TUint attribute( aMessage.Int0() );
    TInt  returnCode( aMessage.Int1() );

    TUint desLen = aMessage.GetDesLength( 2 );

    // Max allowed data size is 512 bytes
    if ( desLen > KConnMonMaxPluginDataSize )
        {
        return KErrTooBig;
        }

    // Allocate a buffer for reading
    HBufC8* buf = HBufC8::New( desLen );
    TPtr8 initptr = buf->Des();

    // read the contents of the client pointer into a TPtr.
    TInt res = aMessage.Read( 2, initptr );

    if ( res != KErrNone )
        {
        delete buf;
        iSession->iCmServer->PanicClient( EBadDescriptor );

        return KErrBadHandle;
        }

    TInt count = iClientRequests.Count();

    // Complete all outstanding client request for this attribute
    for ( TInt i = 0; i < count; i++ )
        {
        const TClientRequest* req = &( iClientRequests[i] );

        if ( static_cast< TInt >( attribute ) == req->iMessage.Int2( ) )
            {
            // Found a request matching the attribute
            switch ( req->iType )
                {
                case EReqGetIntAttribute:
                    {
                    if ( desLen != sizeof( TInt ) )
                        {
                        req->iMessage.Complete( KErrArgument );
                        break;
                        }

                    TInt value = static_cast< TInt >( *initptr.Ptr() );

                    LOGIT4("SERVER: Attribute from plugin, id <%d>, attr <%d>, -> value <%d>, ret <%d>", iPluginId, attribute, value, returnCode )

                    TPtr8 n( reinterpret_cast< TUint8* >( &value ),
                             sizeof( TInt ),
                             sizeof( TInt ) );

                    res = req->iMessage.Write( KAttributeParameterIndex, n );

                    if ( res != KErrNone )
                        {
                        PanicWaitingClient( EBadDescriptor, req->iMessage );
                        }
                    else
                        {
                        req->iMessage.Complete( returnCode );
                        }

                    break;
                    }
                case EReqGetUintAttribute:
                    {
                    if ( desLen != sizeof( TUint ) )
                        {
                        req->iMessage.Complete( KErrArgument );
                        break;
                        }

                    TUint value = static_cast< TUint >( *initptr.Ptr() );

                    LOGIT4("SERVER: Attribute from plugin, id <%d>, attr <%d>, -> value <%d>, ret <%d>", iPluginId, attribute, value, returnCode )

                    TPtr8 n( reinterpret_cast< TUint8* >( &value ),
                             sizeof( TUint ),
                             sizeof( TUint ) );

                    res = req->iMessage.Write( KAttributeParameterIndex, n );

                    if ( res != KErrNone )
                        {
                        PanicWaitingClient( EBadDescriptor, req->iMessage );
                        }
                    else
                        {
                        req->iMessage.Complete( returnCode );
                        }
                    break;
                    }
                case EReqGetBoolAttribute:
                    {
                    if ( desLen != sizeof( TBool ) )
                        {
                        req->iMessage.Complete( KErrArgument );
                        break;
                        }

                    TBool value = static_cast< TBool >( *initptr.Ptr() );

                    LOGIT4("SERVER: Attribute from plugin, id <%d>, attr <%d>, -> value <%d>, ret <%d>", iPluginId, attribute, value, returnCode )

                    TPtr8 n( reinterpret_cast< TUint8* >( &value ),
                             sizeof( TBool ),
                             sizeof( TBool ) );

                    res = req->iMessage.Write( KAttributeParameterIndex, n );

                    if ( res != KErrNone )
                        {
                        PanicWaitingClient( EBadDescriptor, req->iMessage );
                        }
                    else
                        {
                        req->iMessage.Complete( returnCode );
                        }

                    break;
                    }
                 case EReqGetPckgAttribute:
                    {
                    // Write as such to the client area since this is TDes8
                    LOGIT3("SERVER: Attribute from plugin, id <%d>, attr <%d>, -> ret <%d>", iPluginId, attribute, returnCode )

                    res = req->iMessage.Write( KAttributeParameterIndex, initptr );

                    if ( res != KErrNone )
                        {
                        PanicWaitingClient( EBadDescriptor, req->iMessage );
                        }
                    else
                        {
                        req->iMessage.Complete( returnCode );
                        }
                    break;
                    }
                 case EReqGetStringAttribute:
                    {
                    // String is a 16-bit descriptor.
                    // Allocate a 16-bit buffer for reading the string.
                    HBufC* buf16 = HBufC::New( desLen );
                    TPtr initptr16 = buf16->Des();

                    // read the contents of the client pointer into a TPtr.
                    res = aMessage.Read( 2, initptr16 );

                    if ( res != KErrNone )
                        {
                        delete buf;
                        delete buf16;
                        iSession->iCmServer->PanicClient( EBadDescriptor );

                        return KErrBadHandle;
                        }

                    LOGIT3("SERVER: Attribute from plugin, id <%d>, attr <%d>, -> ret <%d>", iPluginId, attribute, returnCode )

                    res = req->iMessage.Write( KAttributeParameterIndex, initptr16 );

                    if ( res != KErrNone )
                        {
                        PanicWaitingClient( EBadDescriptor, req->iMessage );
                        }
                    else
                        {
                        req->iMessage.Complete( returnCode );
                        }

                    delete buf16;

                    break;
                    }
                 default:
                    {
                    delete buf;
                    return KErrNotSupported;
                    }
                } // switch

            // Remove the query because it has been served
            iClientRequests.Remove( i );
            count--;
            i--;
            }  // if
        } // For

    delete buf;

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CPlugin::GetQuery
// -----------------------------------------------------------------------------
//
TInt CPlugin::GetQuery()
    {
    if ( !iPluginReqActive )
        {
        return KErrNotReady;
        }

    // Check if there is a client request waiting in the queue
    TInt count = iClientRequests.Count();

    for ( TInt i = 0; i < count; i++ )
        {
        if ( !iClientRequests[i].iPending )
            {
            TInt attribute( iClientRequests[i].iMessage.Int2() );
            TInt data( iClientRequests[i].iMessage.Int3() );

            // Send the attribute request to the plug-in
            TAttributeRequest req( iClientRequests[i].iType, attribute, 0 );

            if ( req.iType == EReqSetIntAttribute ||
                 req.iType == EReqSetUintAttribute ||
                 req.iType == EReqSetBoolAttribute )
                {
                req.iData = data;
                }
            else if ( req.iType == EReqInternalSetThreshold )
                {
                req.iType      = EReqSetUintAttribute;
                req.iAttribute = KBearerAvailabilityThreshold;
                req.iData      = 1;
                }
            else if ( req.iType == EReqInternalResetThreshold )
                {
                req.iType      = EReqSetUintAttribute;
                req.iAttribute = KBearerAvailabilityThreshold;
                req.iData      = 0;
                }

            TPtr8 n( reinterpret_cast< TUint8* >( &req ),
                     sizeof( TAttributeRequest ),
                     sizeof( TAttributeRequest ) );

            TInt res = iPluginReqMessage.Write( 0, n );

            if ( res != KErrNone )
                {
                iSession->iCmServer->PanicClient( EBadDescriptor );
                }
            else
                {
                // Complete the message
                iPluginReqMessage.Complete( KErrNone );
                }

            iPluginReqActive=EFalse;

            if ( req.iType == EReqSetIntAttribute ||
                 req.iType == EReqSetUintAttribute ||
                 req.iType == EReqSetBoolAttribute ||
                 req.iType == EReqSetStringAttribute ||
                 req.iType == EReqSetPckgAttribute )
                {
                // This request is synchronous and has already been completed
                iClientRequests.Remove( i );
                count--;
                i--;
                }

            return KErrNone;
            }
        }

    // Queue was empty.
    // Just wait for a client request to arrive.
    return KRequestPending;
    }

// -----------------------------------------------------------------------------
// CPlugin::GetQuery
// -----------------------------------------------------------------------------
//
TInt CPlugin::GetQuery( const RMessage2& aMessage )
    {
    __ASSERT_DEBUG( !iPluginReqActive, PanicServer( EReceiveAlreadyActive ) );

    LOGIT("SERVER: EReqPluginGetQuery")

    // Remember attribute request
    iPluginReqMessage = aMessage;
    iPluginReqBuffer = aMessage.Ptr0();
    iPluginReqActive = ETrue;

    return GetQuery();
    }

// -----------------------------------------------------------------------------
// CPlugin::CancelGetQuery
// -----------------------------------------------------------------------------
//
TInt CPlugin::CancelGetQuery()
    {
    LOGIT("SERVER: EReqPluginCancelGetQuery")

    if ( iPluginReqActive )
        {
        iPluginReqMessage.Complete( KErrCancel );
        iPluginReqActive = EFalse;
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CPlugin::GetAttributeForClient
// From a CLIENT.
// -----------------------------------------------------------------------------
//
TInt CPlugin::GetAttributeForClient( const TInt aType, const RMessage2& aMessage )
    {
    LOGENTRFN("CPlugin::GetAttributeForClient()")
    TUint connectionId( aMessage.Int0() );
    TUint attribute( aMessage.Int2() );
    TInt data( aMessage.Int3() );

    if ( aType == EReqInternalSetThreshold || aType == EReqInternalResetThreshold )
        {
        connectionId = iPluginId;
        attribute = KBearerAvailabilityThreshold;
        }

    if ( connectionId <= KMaxConnectionId )
        {
        // Client is asking an attribute using a normal connectionID instead of pluginID.
        TInt bearer( EBearerUnknown );
        TBearerInfo bearerInfo;

        TInt ret = iSession->iCmServer->Iap()->GetBearer( connectionId, bearer, bearerInfo );

        if ( ret == KErrNone )
            {
            // Find the corresponding pluginID
            if ( bearer == EBearerWLAN )
                {
                connectionId = EBearerIdWLAN;
                }
            else if ( bearer == EBearerLAN )
                {
                connectionId = EBearerIdLAN;
                }
            }
        }

    // Check that request is aimed to this plugin.
    if ( connectionId != iPluginId )
        {
        LOGEXITFN1("CPlugin::GetAttributeForClient()", KErrNotSupported)
        return KErrNotSupported;
        }

    if ( aType == EReqSetStringAttribute || aType == EReqSetPckgAttribute )
        {
        // Setting string or packaged attributes is not supported
        LOGEXITFN1("CPlugin::GetAttributeForClient()", KErrNotSupported)
        return KErrNotSupported;
        }

    for ( TInt i = 0; i < iAttributesSupported.Count(); i++ )
        {
        if ( iAttributesSupported[i] == attribute )
            {
            TAttributeRequest req( aType, attribute, 0 );

            if ( aType == EReqSetIntAttribute ||
                 aType == EReqSetUintAttribute ||
                 aType == EReqSetBoolAttribute )
                {
                req.iData = data;
                }
            else if ( aType == EReqInternalSetThreshold )
                {
                req.iType = EReqSetUintAttribute;
                req.iData = 1;
                }
            else if ( aType == EReqInternalResetThreshold )
                {
                req.iType = EReqSetUintAttribute;
                req.iData = 0;
                }

            if ( iPluginReqActive )
                {
                TBool pending( ETrue );

                // Send the attribute request to the plug-in
                TPtr8 n( reinterpret_cast< TUint8* >( &req ),
                         sizeof( TAttributeRequest ),
                         sizeof( TAttributeRequest ) );

                TInt res = iPluginReqMessage.Write( 0, n );

                if ( res != KErrNone )
                    {
                    PanicWaitingClient( EBadDescriptor, iPluginReqMessage );
                    pending = EFalse;
                    }
                else
                    {
                    // Complete the message
                    iPluginReqMessage.Complete( KErrNone );
                    }

                iPluginReqActive=EFalse;

                // Add the request to queue
                // aPending is ETrue
                if ( aType == EReqGetIntAttribute ||
                     aType == EReqGetUintAttribute ||
                     aType == EReqGetBoolAttribute ||
                     aType == EReqGetStringAttribute ||
                     aType == EReqGetPckgAttribute )
                    {
                    TClientRequest clientReq( aType, pending, aMessage );
                    iClientRequests.Append( clientReq );
                    }
                }
            else
                {
                // Add the request to the queue
                // aPending is EFalse
                TClientRequest clientReq( aType, EFalse, aMessage );
                iClientRequests.Append( clientReq );
                }

            LOGEXITFN1("CPlugin::GetAttributeForClient()", KRequestPending)
            return KRequestPending;
            }
        }

    LOGEXITFN1("CPlugin::GetAttributeForClient()", KErrNotSupported)
    return KErrNotSupported;
    }

// -----------------------------------------------------------------------------
// CPlugin::CancelGetAttributeForClient
// From a CLIENT.
// -----------------------------------------------------------------------------
//
void CPlugin::CancelGetAttributeForClient( const RThread& aClient, const TInt aType )
    {
    TInt count = iClientRequests.Count();

    for ( TInt i = 0; i < count; i++ )
        {
        const TClientRequest* req = &( iClientRequests[i] );

        RThread client;

        TInt err = req->iMessage.Client( client );

        if ( err == KErrNone )
            {
            if  ( ( static_cast< TUint >( aType ) == req->iType )  &&
                  ( client.Id() == aClient.Id() ) )
                {
                req->iMessage.Complete( KErrCancel );

                iClientRequests.Remove( i );
                count--;
                i--;
                }

            client.Close();
            }
        }
    }

// -----------------------------------------------------------------------------
// CPlugin::SetAttributeForClient
// From a CLIENT.
// -----------------------------------------------------------------------------
//
TInt CPlugin::SetAttributeForClient( const TInt aType, const RMessage2& aMessage )
    {
    TInt ret = GetAttributeForClient( aType, aMessage );

    if ( ret == KRequestPending )
        {
        // Complete immediately
        return KErrNone;
        }
    else
        {
        return ret;
        }
    }

// -----------------------------------------------------------------------------
// CPlugin::PanicWaitingClient
// -----------------------------------------------------------------------------
//
void CPlugin::PanicWaitingClient( TInt aPanic, const RMessage2& aMessage ) const
    {
    // Let's have a look before we panic the client
    __DEBUGGER()

    // Ok, go for it
    RThread client;

    TInt err =  aMessage.Client( client );

    if ( err == KErrNone )
        {
        _LIT( KPanicMessage, "ConnMonServ" );
        client.Panic( KPanicMessage, aPanic );
        client.Close();
        }
    }

// End-of-file