connectionmonitoring/connmon/connectionmonitor/src/ConnMonServ.cpp
changeset 0 5a93021fdf25
child 2 086aae6fc07e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connectionmonitoring/connmon/connectionmonitor/src/ConnMonServ.cpp	Thu Dec 17 08:55:21 2009 +0200
@@ -0,0 +1,878 @@
+/*
+* Copyright (c) 2002-2009 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:  Connection Monitor server.
+*
+*/
+
+#include <featmgr.h>
+#include <rconnmon.h>
+
+#include "ConnMonServ.h"
+#include "ConnMonDef.h"
+#include "ConnMonIAP.h"
+#include "ConnMonSess.h"
+#include "CEventQueue.h"
+#include "log.h"
+
+#include "ConnMonAvailabilityManager.h"
+#include "connmoncommsdatcache.h"
+#include "ConnMonBearerCSD.h"
+#include "ConnMonBearerGPRS.h"
+#include "ConnMonBearerLAN.h"
+#include "ConnMonBearerWLAN.h"
+#include "ConnMonBearerGroupManager.h"
+#include "connmoncommsdatnotifier.h"
+
+// ============================ LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// PanicServer
+// Panics the server in case of programming error.
+// -----------------------------------------------------------------------------
+//
+void PanicServer( TInt aPanic )
+    {
+    _LIT( KPanicCategory, "ConnectionMonitor Server" );
+    User::Panic( KPanicCategory, aPanic );
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CConnMonScheduler::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CConnMonScheduler::ConstructL()
+    {
+    // Construct active scheduler
+    CConnMonScheduler* self = new( ELeave ) CConnMonScheduler;
+    CActiveScheduler::Install( self );
+
+    // Construct server
+    self->iServer = new( ELeave ) CConnMonServer;
+    self->iServer->ConstructL();
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonScheduler::~CConnMonScheduler
+// -----------------------------------------------------------------------------
+//
+CConnMonScheduler::~CConnMonScheduler()
+    {
+    delete iServer;
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonScheduler::LaunchFromClient
+// -----------------------------------------------------------------------------
+//
+TInt CConnMonScheduler::LaunchFromClient()
+    {
+    LOGENTRFN("CConnMonScheduler::LaunchFromClient()")
+    TInt err( KErrNone );
+
+    // Set up waiting apparatus
+    TRequestStatus status;
+    TSignal signal( status );
+
+    // Create semaphore to allow to signal when server has started
+    RSemaphore globStartSignal;
+
+    LOGTIMINGSTART("CConnMonScheduler::LaunchFromClient()")
+
+    err = globStartSignal.CreateGlobal( KConnMonStartupSemaphore, 0 );
+    if ( err != KErrNone )
+        {
+        // If semaphore already exists, open it and wait
+        err = globStartSignal.OpenGlobal( KConnMonStartupSemaphore, EOwnerProcess );
+        if ( KErrNone == err )
+            {
+            LOGIT("LaunchFromClient: semaphore in use, waiting release...")
+            globStartSignal.Wait();
+            globStartSignal.Signal();
+            globStartSignal.Close();
+            LOGTIMINGEND("CConnMonScheduler::LaunchFromClient() (waiting)")
+            LOGIT("LaunchFromClient: semaphore released")
+            }
+        else
+            {
+            LOGIT1("LaunchFromClient: semaphore in use, but open failed <%d>", err)
+            }
+        LOGEXITFN1("CConnMonScheduler::LaunchFromClient()", err)
+        return err;
+        }
+
+    RProcess server;
+    err = server.Create(
+            KConnectionMonitorServerExe,
+            signal.Get(),
+            TUidType( KNullUid, KNullUid, KConnMonServerUid ),
+            EOwnerThread );
+    if ( err != KErrNone )
+        {
+        LOGIT1("LaunchFromClient: ERROR, server creation failed <%d>", err)
+        LOGEXITFN1("CConnMonScheduler::LaunchFromClient()", err)
+        return err;
+        }
+
+    server.Rendezvous( status );
+    if ( status != KRequestPending )
+        {
+        server.Kill( 0 ); // Abort startup
+        }
+    else
+        {
+        server.Resume(); // Logon OK - start the server
+        }
+
+    // Wait for launch to complete
+    User::WaitForRequest( status );
+
+    // We can't use the 'exit reason' if the server panicked as this is the
+    // panic 'reason' and may be '0' which cannot be distinguished from KErrNone
+    if ( server.ExitType() == EExitPanic )
+        {
+        LOGIT2("LaunchFromClient: ERROR, server start PANIC, reason: %d, status: %d", server.ExitReason(), status.Int())
+        err = KErrGeneral;
+        }
+    else
+        {
+        err = status.Int();
+        }
+
+    server.Close();
+
+    // Signal other clients that server process has started
+    globStartSignal.Signal();
+
+    // Delete semaphore
+    globStartSignal.Close();
+
+    LOGTIMINGEND("CConnMonScheduler::LaunchFromClient() (real)")
+    LOGEXITFN1("CConnMonScheduler::LaunchFromClient()", err)
+    return err;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CConnMonScheduler::ThreadStart
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CConnMonScheduler::ThreadStart( TSignal& /*aSignal*/ )
+    {
+    __UHEAP_MARK;
+    LOGENTRFN("CConnMonScheduler::ThreadStart()")
+    TInt err( KErrNone );
+
+    // Get cleanup stack
+    CTrapCleanup* cleanup = CTrapCleanup::New();
+    // Initialize all up to and excluding starting scheduler
+    if ( cleanup )
+        {
+        TRAP( err, ConstructL() );
+        }
+    else
+        {
+        err = KErrNoMemory;
+        }
+
+    // Tell starting thread we've started and start the active scheduler
+    // Scheduler will "sit" here while the server is running because
+    // Start() will return only when server calls CActiveScheduler::Stop().
+    if ( KErrNone == err )
+        {
+        RProcess::Rendezvous( KErrNone );
+        CActiveScheduler::Start();
+        }
+
+    // Close things down because server has died
+    delete CActiveScheduler::Current();
+    delete cleanup;
+
+    __UHEAP_MARKEND;
+    LOGEXITFN1("CConnMonScheduler::ThreadStart()", err)
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonScheduler::Error
+// -----------------------------------------------------------------------------
+//
+void CConnMonScheduler::Error( TInt aError ) const
+    {
+    // Panic if error didn't arise from server
+    if ( iServer->IsActive() )
+        {
+        PanicServer( EErrorFromNonClientObject );
+        }
+
+    // If it's a bad descriptor, panic the client
+    if ( aError == KErrBadDescriptor )
+        {
+        iServer->PanicClient( EBadDescriptor );
+        }
+
+    iServer->Error( aError );
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::CConnMonServer
+// -----------------------------------------------------------------------------
+//
+CConnMonServer::CConnMonServer()
+        :
+        CPolicyServer( CActive::EPriorityStandard, KConnMonPolicy ),
+        iAvailabilityManager( NULL )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::ConstructL()
+    {
+    LOGENTRFN("CConnMonServer::ConstructL()")
+    LOGIT("ConstructL: Server trying to start...")
+
+    // Naming the server thread after the server helps debugging panics.
+    RThread::RenameMe( KConnectionMonitorServerName );
+
+    // Construct IAP wrapper
+    iIap = new( ELeave ) CConnMonIAP( this );
+    iIap->ConstructL();
+
+    // Construct event queue
+    iEventQueue = new( ELeave ) CEventQueue;
+    iEventQueue->ConstructL( this );
+
+    // Create the object container index
+    iContainerIndex = CObjectConIx::NewL();
+
+    // Construct shutdown timer
+    iShutdown = new( ELeave ) CConnMonDelayedShutdown( this );
+    iShutdown->ConstructL();
+
+
+    ////// Availability stuff
+
+    // CommsDat cache
+    iCommsDatCache = CConnMonCommsDatCache::NewL();
+
+    // Add bearers to array
+    User::LeaveIfError(
+            iBearers.Append( new( ELeave ) TConnMonBearerCSD( iIap, iCommsDatCache ) ) );
+    User::LeaveIfError(
+            iBearers.Append( new( ELeave ) TConnMonBearerGPRS( iIap, iCommsDatCache ) ) );
+    User::LeaveIfError(
+            iBearers.Append( new( ELeave ) TConnMonBearerLAN( iIap, iCommsDatCache ) ) );
+
+    // Initialize FeatureManager
+    FeatureManager::InitializeLibL();
+
+    #ifndef __WINSCW__  // WINS does not support WLAN
+    // Check if WLAN is enabled
+    if ( FeatureManager::FeatureSupported( KFeatureIdProtocolWlan ) )
+        {
+        User::LeaveIfError(
+                iBearers.Append( new( ELeave ) TConnMonBearerWLAN( iIap, iCommsDatCache ) ) );
+        }
+    #endif
+    LOGIT1("ConstructL: iBearers constructed, count <%d>", iBearers.Count() )
+
+    // Initialize the CommsDat cache. Will read the necessary CommsDat tables
+    // and populate the cache tables with current information. Any changes
+    // after this init phase will trigger ConnMon events when appropriate.
+    iCommsDatCache->Init( this, iIap, &iBearers );
+
+    // IAP / SNAP availability manager
+    iAvailabilityManager = CConnMonAvailabilityManager::NewL(
+            iCommsDatCache,
+            this );
+
+    // Central Repository notifiers
+    iIapTableNotifier = CConnMonCommsDatNotifier::NewL(
+            iAvailabilityManager,
+            iCommsDatCache->GetIapRecordTableId() );
+    iSnapTableNotifier = CConnMonCommsDatNotifier::NewL(
+            iAvailabilityManager,
+            iCommsDatCache->GetSnapRecordTableId() );
+    iVirtualTableNotifier = CConnMonCommsDatNotifier::NewL(
+            iAvailabilityManager,
+            iCommsDatCache->GetVirtualRecordTableId() );
+    LOGIT("ConstructL: Availability manager and CenRep notifiers constructed")
+
+    // Bearer group manager
+    iBearerGroupManager = CConnMonBearerGroupManager::NewL();
+    LOGIT("ConstructL: Bearer group manager constructed")
+
+    // Identify ourselves and open for service
+    StartL( KConnectionMonitorServerName );
+
+    LOGIT("ConstructL: Server started successfully")
+    LOGEXITFN("CConnMonServer::ConstructL()")
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::~CConnMonServer
+// -----------------------------------------------------------------------------
+//
+CConnMonServer::~CConnMonServer()
+    {
+    LOGIT("Server: Running destructor")
+
+    delete iIap;
+    delete iEventQueue;
+    delete iContainerIndex;
+    delete iShutdown;
+
+    // Bearers to array
+    iBearers.ResetAndDestroy();
+    iBearers.Close();
+
+    // Availability manager
+    delete iAvailabilityManager;
+
+    // CenRep notification listeners
+    if ( iIapTableNotifier )
+        {
+        iIapTableNotifier->Cancel();
+        }
+    if ( iSnapTableNotifier )
+        {
+        iSnapTableNotifier->Cancel();
+        }
+    if ( iVirtualTableNotifier )
+        {
+        iVirtualTableNotifier->Cancel();
+        }
+    delete iIapTableNotifier;
+    delete iSnapTableNotifier;
+    delete iVirtualTableNotifier;
+
+    // CommsDat cache
+    delete iCommsDatCache;
+
+    // Bearer Group Manager
+    delete iBearerGroupManager;
+
+    FeatureManager::UnInitializeLib();
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::NewSessionL
+// -----------------------------------------------------------------------------
+//
+CSession2* CConnMonServer::NewSessionL(
+        const TVersion& /*aVersion*/,
+        const RMessage2& /*aMessage*/ ) const
+    {
+    CConnMonSession* session = new( ELeave ) CConnMonSession(
+            CONST_CAST( CConnMonServer*, this ) );
+
+    CleanupStack::PushL( session );
+    session->ConstructL();
+    CleanupStack::Pop( session );
+    CONST_CAST( CConnMonServer*, this )->IncrementSessions();
+    return session;
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::IncrementSessions
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::IncrementSessions()
+    {
+    iSessionCount++;
+    iShutdown->Cancel();
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::DecrementSessions
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::DecrementSessions()
+    {
+    iSessionCount--;
+
+    if ( iSessionCount > 0 )
+        {
+        return;
+        }
+    if ( !iShutdown->IsActive() )
+        {
+        iShutdown->Start();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::SendEventToSessions
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::SendEventToSessions( const TEvent& aEvent, TInt& aNumOffered )
+    {
+    CSession2* session;
+
+    // Iterate through sessions
+    iSessionIter.SetToFirst();
+    for ( session = iSessionIter++; session; session = iSessionIter++ )
+        {
+        CConnMonSession* cmsession = static_cast<CConnMonSession*>( session );
+        if ( cmsession->CanReceiveEvent() )
+            {
+            cmsession->SendEventToClient( aEvent );
+            ++aNumOffered;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::SendDataVolumesToSessions
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::SendDataVolumesToSessions(
+        const TUint aConnectionId,
+        const TUint aDlData,
+        const TUint aUlData,
+        const TInt  aStatus )
+    {
+    CSession2* session;
+
+    // Iterate through sessions
+    iSessionIter.SetToFirst();
+    for ( session = iSessionIter++; session; session = iSessionIter++ )
+        {
+        ( static_cast<CConnMonSession*>( session ) )->CompleteDataVolumeRequests(
+                aConnectionId,
+                aDlData,
+                aUlData,
+                aStatus );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::SendActivityToSessions
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::SendActivityToSessions(
+        const TUint aConnectionId,
+        const TBool aActivity,
+        const TInt  aStatus )
+    {
+    CSession2* session;
+
+    // Iterate through sessions
+    iSessionIter.SetToFirst();
+    for ( session = iSessionIter++; session; session = iSessionIter++ )
+        {
+        ( static_cast<CConnMonSession*>( session ) )->CompleteActivityRequests(
+                aConnectionId,
+                aActivity,
+                aStatus );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::RemoveConnSettingsFromSessions
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::RemoveConnSettingsFromSessions( const TUint aConnectionId )
+    {
+    CSession2* session;
+
+    // Iterate through sessions
+    iSessionIter.SetToFirst();
+    for ( session = iSessionIter++; session; session = iSessionIter++ )
+        {
+        ( static_cast<CConnMonSession*>( session ) )->RemoveConnectionParams(
+                aConnectionId );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::NumberOfListeners
+// -----------------------------------------------------------------------------
+//
+TInt CConnMonServer::NumberOfListeners()
+    {
+    CSession2* session;
+    CSession2* original;
+    TInt count( 0 );
+
+    original = iSessionIter;
+
+    // Iterate through sessions
+    iSessionIter.SetToFirst();
+    for ( session = iSessionIter++; session; session = iSessionIter++ )
+        {
+        if ( ( static_cast<CConnMonSession*>( session ) )->IsListening() )
+            {
+            ++count;
+            }
+        }
+
+    // Reset session iterator
+    if ( original != 0 )
+        {
+        iSessionIter.Set( *original );
+        }
+
+    return count;
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::CalculateThreshold
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::CalculateThreshold(
+        const TUint aConnectionId,
+        const TInt& aThresholdType,
+        TUint& aThreshold )
+    {
+    CSession2* session;
+    CSession2* original;
+    TUint th( 0 );
+
+    aThreshold = 0;
+    original = iSessionIter;
+
+    // Iterate through sessions to find the smallest threshold
+    iSessionIter.SetToFirst();
+    for ( session = iSessionIter++; session; session = iSessionIter++ )
+        {
+        if ( aThresholdType == EBearerAvailabilityThreshold ||
+                aThresholdType == ESignalStrengthThreshold )
+            {
+            // Bearer specific thresholds
+            ( static_cast<CConnMonSession*>( session ) )->GetBearerThreshold(
+                    aThresholdType,
+                    th );
+
+            if ( th != 0 )
+                {
+                aThreshold = 1;
+                }
+            }
+        else
+            {
+            // Connection Specific thresholds
+            TConnSettings connSettings( 0, 0, 0 );
+
+            ( static_cast<CConnMonSession*>( session ) )->GetConnectionSettings(
+                    aConnectionId,
+                    connSettings );
+            if ( aThresholdType == EDownlinkThreshold )
+                {
+                th = connSettings.iDLDataThreshold;
+                }
+            else if ( aThresholdType == EUplinkThreshold )
+                {
+                th = connSettings.iULDataThreshold;
+                }
+            else if ( aThresholdType == EActivityTimeThreshold )
+                {
+                th = connSettings.iActivityTimeThreshold;
+                }
+
+            if ( ( th > 0 ) && ( aThreshold == 0 || th < aThreshold ) )
+                {
+                aThreshold = th;
+                }
+            }
+        }
+
+    // Reset session iterator
+    if ( original != 0 )
+        {
+        iSessionIter.Set( *original );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::NewContainerL
+// -----------------------------------------------------------------------------
+//
+CObjectCon* CConnMonServer::NewContainerL()
+    {
+    return iContainerIndex->CreateL();
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::RemoveContainer
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::RemoveContainer( CObjectCon* aContainer )
+    {
+    iContainerIndex->Remove( aContainer );
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::SendRequestToPlugin
+// -----------------------------------------------------------------------------
+//
+TInt CConnMonServer::SendRequestToPlugin(
+        const TInt aType,
+        const RMessage2& aMessage,
+        const TBool aToAllPlugins )
+    {
+    TInt ret( KErrNotSupported );
+    TInt err( KErrNotSupported );
+    CSession2* session;
+
+    if ( FeatureManager::FeatureSupported( KFeatureIdConnMonExtension ) )
+        {
+        // Iterate through sessions
+        iSessionIter.SetToFirst();
+
+        for ( session = iSessionIter++; session; session = iSessionIter++ )
+            {
+            err = ( static_cast<CConnMonSession*>( session ) )->SendRequestToPlugin(
+                    aType,
+                    aMessage );
+
+            if ( ( err == KRequestPending ) || ( err == KErrNone ) )
+                {
+                // OK because a plugin has handled the request.
+                if ( aToAllPlugins )
+                    {
+                    ret = err;
+                    }
+                else
+                    {
+                    return err;
+                    }
+                }
+            }
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::CancelAttributeRequestsFromPlugins
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::CancelAttributeRequestsFromPlugins(
+        const RThread& aClient,
+        const TInt aType )
+    {
+    CSession2* session;
+
+    if ( FeatureManager::FeatureSupported( KFeatureIdConnMonExtension ) )
+        {
+        // Iterate through sessions
+        iSessionIter.SetToFirst();
+
+        for ( session = iSessionIter++; session; session = iSessionIter++ )
+            {
+            ( static_cast<CConnMonSession*>( session ) )->CancelAttributeRequestFromPlugin(
+                    aClient,
+                    aType );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::PanicClient
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::PanicClient( TInt aPanic ) const
+    {
+    // Let's have a look before we panic the client
+    __DEBUGGER()
+
+    // Ok, go for it
+    LOGIT("Server: PanicClient: Sending panic")
+    /*_LIT( KConnectionMonitorServer, "ConnMonServ" );*/
+    /*Message().Panic( KConnectionMonitorServer, aPanic );*/
+    LOGIT1("Server: PanicClient: Panic removed to improve ConnMon robustness, code was <%d>", aPanic )
+    aPanic = aPanic; // To remove warning
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::PanicClient
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::PanicClient( const RMessage2& aMsg, const TInt aPanic ) const
+    {
+    // Let's have a look before we panic the client
+    __DEBUGGER()
+
+    // Ok, go for it
+    LOGIT("Server: PanicClient: Sending panic")
+    /*_LIT( KConnectionMonitorServer, "ConnMonServ" );*/
+    /*aMsg.Panic( KConnectionMonitorServer, aPanic );*/
+    LOGIT1("Server: PanicClient: Panic removed to improve ConnMon robustness, code was <%d>", aPanic )
+    TInt panic = aPanic; // To remove warning
+    panic = aMsg.Int0(); // To remove warning
+    panic = panic; // To remove warning
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::Error
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::Error( TInt aError )
+    {
+    if ( aError != KErrBadDescriptor )
+        {
+        // Anyway, complete the outstanding message
+        Message().Complete( aError );
+        }
+
+    // Ready to roll again
+    ReStart(); // Really means just continue reading client requests
+    }
+
+// -----------------------------------------------------------------------------
+// Get available IAP IDs for the IAPs with bearer aBearerId
+// -----------------------------------------------------------------------------
+//
+TInt CConnMonServer::GetAvailableIaps( const TUint aBearerId, TConnMonIapInfo& aIapInfo )
+    {
+    // Currently CommsDat is read only after a change notification is received
+    // from CenRep about a relevant CommsDat table. If these events are
+    // unreliable, we can increase robustness by reading CommsDat tables again
+    // every time a client asks for IAP/SNAP availability information, but this
+    // will slow down the requests.
+    //
+    // Uncomment the following TRAP to force ConnMon to read CommsDat every
+    // time a client asks for IAP availability (KIapAvailability-attribute).
+    //
+    /*TRAPD( err, iCommsDatCache->RefreshCommsDatCacheL( 0 ) );*/
+    return iCommsDatCache->GetAvailableIaps( aBearerId, aIapInfo );
+    }
+
+// -----------------------------------------------------------------------------
+// Get available SANP IDs
+// -----------------------------------------------------------------------------
+//
+void CConnMonServer::GetAvailableSnaps( TConnMonSNAPInfo& aSnapInfo )
+    {
+    // See comment in CConnMonServer::GetAvailableIaps() (above)
+    /*TRAPD( err, iCommsDatCache->RefreshCommsDatCacheL( 0 ) );*/
+    iCommsDatCache->GetAvailableSnaps( aSnapInfo );
+    }
+
+// -----------------------------------------------------------------------------
+// Get available SANP IDs
+// -----------------------------------------------------------------------------
+//
+TInt CConnMonServer::GetAvailableSnaps( RArray<TConnMonId>& aSnapIds )
+    {
+    // See comment in CConnMonServer::GetAvailableIaps() (above)
+    /*TRAPD( err, iCommsDatCache->RefreshCommsDatCacheL( 0 ) );*/
+    return iCommsDatCache->GetAvailableSnaps( aSnapIds );
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonServer::CustomSecurityCheckL
+// Implements custom security checking for IPCs marked with
+// TSpecialCase::ECustomCheck.
+// -----------------------------------------------------------------------------
+//
+CPolicyServer::TCustomResult CConnMonServer::CustomSecurityCheckL(
+        const RMessage2& aMsg,
+        TInt& /*aAction*/,
+        TSecurityInfo& /*aMissing*/ )
+    {
+    switch ( aMsg.Function() )
+        {
+        case EReqSetBoolAttribute:
+            {
+            switch ( aMsg.Int2() )
+                {
+                case KConnectionStop:
+                case KConnectionStopAll:
+                    {
+                    // NetworkServices + NetworkControl
+                    return ( KConnMonPolicyElements[4].iPolicy.CheckPolicy( aMsg ) ) ?
+                        EPass : EFail;
+                    }
+                default:
+                    return EPass;
+                }
+            }
+        default:
+            return EPass;
+        }
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CConnMonDelayedShutdown::CConnMonDelayedShutdown
+// -----------------------------------------------------------------------------
+//
+CConnMonDelayedShutdown::CConnMonDelayedShutdown( CConnMonServer* aServer )
+        :
+        CActive( EConnMonPriorityNormal ),
+        iServer( aServer )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonDelayedShutdown::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CConnMonDelayedShutdown::ConstructL()
+    {
+    CActiveScheduler::Add( this );
+    User::LeaveIfError( iTimer.CreateLocal() );
+    }
+
+// Destructor
+CConnMonDelayedShutdown::~CConnMonDelayedShutdown()
+    {
+    Cancel();
+    iTimer.Close();
+    iServer = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonDelayedShutdown::Start
+// -----------------------------------------------------------------------------
+//
+void CConnMonDelayedShutdown::Start()
+    {
+    if ( IsActive() )
+        {
+        return;
+        }
+
+    iTimer.After( iStatus, KConnMonShutdownInterval );
+    SetActive();
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonDelayedShutdown::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CConnMonDelayedShutdown::DoCancel()
+    {
+    iTimer.Cancel();
+    }
+
+// -----------------------------------------------------------------------------
+// CConnMonDelayedShutdown::RunL
+// -----------------------------------------------------------------------------
+//
+void CConnMonDelayedShutdown::RunL()
+    {
+    LOGIT("Server: Shutting down by timer")
+    CActiveScheduler::Stop();
+    }
+
+// End-of-file