connectionmonitoring/connmon/connectionmonitor/src/ConnMonServ.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
child 18 fcbbe021d614
child 55 fc7b30ed2058
permissions -rw-r--r--
Revision: 201001 Kit: 201003

/*
* 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"
#include "cellulardatausagekeyupdater.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")
    
    iCellularDataUsageKeyUpdater = CCellularDataUsageKeyUpdater::NewL( this );
    LOGIT("ConstructL: CCellularDataUsageKeyUpdater 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;
    
    delete iCellularDataUsageKeyUpdater;

    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