connectionmonitoring/connmon/connectionmonitor/src/CPlugin.cpp
changeset 0 5a93021fdf25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connectionmonitoring/connmon/connectionmonitor/src/CPlugin.cpp	Thu Dec 17 08:55:21 2009 +0200
@@ -0,0 +1,826 @@
+/*
+* 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