--- /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