diff -r 000000000000 -r 5a93021fdf25 connectionmonitoring/connmon/connectionmonitor/src/connmoncommsdatcache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectionmonitoring/connmon/connectionmonitor/src/connmoncommsdatcache.cpp Thu Dec 17 08:55:21 2009 +0200 @@ -0,0 +1,2046 @@ +/* +* Copyright (c) 2008-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: Provides cached information on IAPs and SNAPs in CommsDat. +* +*/ + +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#endif +#include + +#include "ConnMonServ.h" +#include "CEventQueue.h" +#include "ConnMonIAP.h" +#include "ConnMonBearer.h" +#include "connmoncommsdatcache.h" +#include "log.h" + +using namespace CommsDat; + +TConnMonSnapEntry::TConnMonSnapEntry() + { + iId = 0; + iNextLayerIapId = 0; + iNextLayerSnapId = 0; + iAvailability = 0; + iNextLayerIndex = KErrNotFound; + } + +TConnMonSnapEntry::TConnMonSnapEntry( + TUint aId, + TUint aNextLayerIapId, + TUint aNextLayerSnapId ) + : + iId( aId ), + iNextLayerIapId( aNextLayerIapId ), + iNextLayerSnapId( aNextLayerSnapId ) + { + iAvailability = 0; + iNextLayerIndex = KErrNotFound; + } + +TInt TConnMonSnapEntry::Compare( + const TConnMonSnapEntry& aFirst, + const TConnMonSnapEntry& aSecond ) + { + // Availability info is ignored + if ( aFirst.iId < aSecond.iId ) return -1; + if ( aFirst.iId > aSecond.iId ) return 1; + if ( aFirst.iNextLayerSnapId < aSecond.iNextLayerSnapId ) return -1; + if ( aFirst.iNextLayerSnapId > aSecond.iNextLayerSnapId ) return 1; + if ( aFirst.iNextLayerIapId < aSecond.iNextLayerIapId ) return -1; + if ( aFirst.iNextLayerIapId > aSecond.iNextLayerIapId ) return 1; + return 0; + } + +TInt TConnMonSnapEntry::FindCompare( + const TInt* aKey, + const TConnMonSnapEntry& aEntry ) + { + // Zero if match, negative if first is smaller, positive otherwise + return ( *aKey ) - aEntry.iId; + } + +TBool TConnMonSnapEntry::Match( + const TConnMonSnapEntry& aFirst, + const TConnMonSnapEntry& aSecond ) + { + // Availability info is ignored + if ( ( aFirst.iId == aSecond.iId ) && + ( aFirst.iNextLayerIapId == aSecond.iNextLayerIapId ) && + ( aFirst.iNextLayerSnapId == aSecond.iNextLayerSnapId ) ) + { + return ETrue; + } + return EFalse; + } + + +TConnMonIapEntry::TConnMonIapEntry() + { + iId = 0; + iBearerType = 0; + iServiceType = 0; + iAvailability = 0; + iNextLayerIapId = 0; + iNextLayerSnapId = 0; + iNextLayerIndex = KErrNotFound; + } + +TConnMonIapEntry::TConnMonIapEntry( + TUint aId, + TUint aBearerType, + TUint aServiceType ) + : + iId( aId ), + iBearerType( aBearerType ), + iServiceType( aServiceType ) + { + iAvailability = 0; + iNextLayerIndex = KErrNotFound; + iNextLayerIapId = 0; + iNextLayerSnapId = 0; + } + +TInt TConnMonIapEntry::Compare( + const TConnMonIapEntry& aFirst, + const TConnMonIapEntry& aSecond ) + { + // Zero if match, negative if first is smaller, positive otherwise + // Availability info is ignored + return aFirst.iId - aSecond.iId; + } + +TInt TConnMonIapEntry::FindCompare( + const TInt* aKey, + const TConnMonIapEntry& aEntry ) + { + // Zero if match, negative if first is smaller, positive otherwise + return ( *aKey ) - aEntry.iId; + } + +TBool TConnMonIapEntry::Match( + const TConnMonIapEntry& aFirst, + const TConnMonIapEntry& aSecond ) + { + // Availability info is ignored + if ( ( aFirst.iId == aSecond.iId ) && + ( aFirst.iBearerType == aSecond.iBearerType ) && + ( aFirst.iServiceType == aSecond.iServiceType ) ) + { + return ETrue; + } + return EFalse; + } + + +TConnMonVirtualIapEntry::TConnMonVirtualIapEntry() + { + iId = 0; + iNextLayerIapId = 0; + iNextLayerSnapId = 0; + } + +TConnMonVirtualIapEntry::TConnMonVirtualIapEntry( + TUint aId, + TUint aNextLayerIapId, + TUint aNextLayerSnapId ) + : + iId( aId ), + iNextLayerIapId( aNextLayerIapId ), + iNextLayerSnapId( aNextLayerSnapId ) + { + } + +TInt TConnMonVirtualIapEntry::Compare( + const TConnMonVirtualIapEntry& aFirst, + const TConnMonVirtualIapEntry& aSecond ) + { + // Zero if match, negative if first is smaller, positive otherwise + return aFirst.iId - aSecond.iId; + } + +TInt TConnMonVirtualIapEntry::FindCompare( + const TInt* aKey, + const TConnMonVirtualIapEntry& aEntry ) + { + // Zero if match, negative if first is smaller, positive otherwise + return ( *aKey ) - aEntry.iId; + } + +TBool TConnMonVirtualIapEntry::Match( + const TConnMonVirtualIapEntry& aFirst, + const TConnMonVirtualIapEntry& aSecond ) + { + if ( ( aFirst.iId == aSecond.iId ) && + ( aFirst.iNextLayerIapId == aSecond.iNextLayerIapId ) && + ( aFirst.iNextLayerSnapId == aSecond.iNextLayerSnapId ) ) + { + return ETrue; + } + return EFalse; + } + + +// --------------------------------------------------------------------------- +// Two phased constructor. +// --------------------------------------------------------------------------- +// +CConnMonCommsDatCache* CConnMonCommsDatCache::NewL() + { + //LOGENTRFN("CConnMonCommsDatCache::NewL()") + + CConnMonCommsDatCache* self = CConnMonCommsDatCache::NewLC(); + CleanupStack::Pop( self ); + + //LOGEXITFN("CConnMonCommsDatCache::NewL()") + return self; + } + +// --------------------------------------------------------------------------- +// Two phased constructor. +// --------------------------------------------------------------------------- +// +CConnMonCommsDatCache* CConnMonCommsDatCache::NewLC() + { + //LOGENTRFN("CConnMonCommsDatCache::NewLC()") + + CConnMonCommsDatCache* self = new( ELeave ) CConnMonCommsDatCache; + CleanupStack::PushL( self ); + self->ConstructL(); + + //LOGEXITFN("CConnMonCommsDatCache::NewLC()") + return self; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CConnMonCommsDatCache::~CConnMonCommsDatCache() + { + LOGENTRFN("CConnMonCommsDatCache::~CConnMonCommsDatCache()") + + if ( iSnapCache ) + { + iSnapCache->Close(); + delete iSnapCache; + iSnapCache = NULL; + } + if ( iIapCache ) + { + iIapCache->Close(); + delete iIapCache; + iIapCache = NULL; + } + if ( iVirtualIapCache ) + { + iVirtualIapCache->Close(); + delete iVirtualIapCache; + iVirtualIapCache = NULL; + } + + iWlanIapIdCache.Close(); + iIapIdCache.Close(); + iSnapIdCache.Close(); + + LOGEXITFN("CConnMonCommsDatCache::~CConnMonCommsDatCache()") + } + +// --------------------------------------------------------------------------- +// Reads all IAP and SNAP information from CommsDat and initializes the cache +// with it. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::Init( + CConnMonServer* aServer, + CConnMonIAP* aConnMonIap, + RPointerArray* aBearers ) + { + LOGENTRFN("CConnMonCommsDatCache::Init()") + + iServer = aServer; + iIap = aConnMonIap; + iBearers = aBearers; + + if ( iInitStatus != EConnMonCacheInitNotStarted ) + { + LOGIT("Init: ERROR, ConnMon CommsDat cache init called too many times") + return; + } + iInitStatus = EConnMonCacheInitInProgress; + + // Check if WLAN bearer is available + for ( TInt i = 0; i < iBearers->Count(); i++ ) + { + if ( (*iBearers)[i]->BearerId() == EBearerIdWLAN ) + { + iWlanSupportEnabled = ETrue; + break; + } + } + + TRAPD( leaveCode, InitCommsDatCacheL() ); + if ( leaveCode ) + { + LOGIT1("Init: ERROR (Ok if empty), LEAVE in ConnMon CommsDat cache init <%d>", leaveCode) + } + + RefreshAvailabilityInfo( EFalse ); // Never send events in Init phase + iInitStatus = EConnMonCacheInitCompleted; + + LOGEXITFN("CConnMonCommsDatCache::Init()") + } + +// --------------------------------------------------------------------------- +// Calls the correct method to read the CommsDat table, refered to with +// parameter aTableId, to cache. This should be called when a change is +// detected in CommsDat through central repository events. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::RefreshCommsDatCacheL( const TUint32 aTableId ) + { + //LOGENTRFN("CConnMonCommsDatCache::RefreshCommsDatCacheL()") + + CMDBSession* db = CMDBSession::NewLC( CMDBSession::LatestVersion() ); + db->SetAttributeMask( ECDHidden | ECDProtectedWrite ); + + if ( aTableId == iIapRecordTableId ) + { + LOGIT("RefreshCommsDatCacheL: IAP table change event") + RefreshCommsDatIapCacheL( *db ); + } + else if ( aTableId == iSnapRecordTableId ) + { + LOGIT("RefreshCommsDatCacheL: SNAP table change event") + RefreshCommsDatSnapCacheL( *db ); + } + else if ( aTableId == iVirtualRecordTableId ) + { + LOGIT("RefreshCommsDatCacheL: Virtual record table change event") + RefreshCommsDatVirtualIapCacheL( *db ); + } + else if ( aTableId == 0 ) + { + // This option is not currently used, but provided to support the + // possibility to read CommsDat information again when client is + // asking for IAP/SNAP availability information as a request. + // This would be needed in the case that CenRep change events + // become unreliable for some reason, and thus the CommsDat cache + // would not be reliably up to date. + LOGIT("RefreshCommsDatCacheL: Reading all commsdat tables") + RefreshCommsDatIapCacheL( *db ); + RefreshCommsDatSnapCacheL( *db ); + RefreshCommsDatVirtualIapCacheL( *db ); + } + + CleanupStack::PopAndDestroy( db ); + + //LOGEXITFN("CConnMonCommsDatCache::RefreshCommsDatCacheL()") + } + +// --------------------------------------------------------------------------- +// Solves IAP and SNAP availability. The availability information in the cache +// tables will be up to date after a call to this method. +// If parameter aCanSendEvents is true, availability changed events will be +// sent to clients if any changes from previous availability state is detected. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::RefreshAvailabilityInfo( const TBool aCanSendEvents ) + { + LOGENTRFN("CConnMonCommsDatCache::RefreshAvailabilityInfo()") + + // If any relevant commsdat table changed. + // + // These flags are set to true only when CommsDat change event is received, + // CommsDat information is read into ConnMon cache, and that information + // has changed. + if ( iIapsChanged || iSnapsChanged || iVirtualIapsChanged ) + { + UpdateSnapAndVirtualIapLinks(); + iIapsChanged = EFalse; + iSnapsChanged = EFalse; + iVirtualIapsChanged = EFalse; + } + + ResetAllAvailabilityInfo(); + for ( TInt i = 0; i < iBearers->Count(); i++ ) + { + (*iBearers)[i]->FlagAvailableIaps(); + } + SolveSnapAndVirtualIapAvailability(); + + LOGIT(".") + TBool availableIapsChanged = UpdateAvailableIaps(); + + #ifdef _DEBUG + // Print available IAP IDs to log + for ( TInt j = 0; j < iIapCache->Count(); j++ ) + { + if ( (*iIapCache)[j].iAvailability == EConnMonAvailabilityAvailable ) + { + TUint currentId = (*iIapCache)[j].iId; + if ( (*iIapCache)[j].iBearerType == EConnMonCacheBearerTypeVirtual ) + { + switch ( (*iIapCache)[j].iServiceType ) + { + case EConnMonCacheServiceTypeCsd: + LOGIT1(" %3d: CSD, virtual", currentId) break; + case EConnMonCacheServiceTypeGprs: + LOGIT1(" %3d: GPRS, virtual", currentId) break; + case EConnMonCacheServiceTypeLan: + LOGIT1(" %3d: LAN, virtual", currentId) break; + case EConnMonCacheServiceTypeWlan: + LOGIT1(" %3d: WLAN, virtual", currentId) break; + default: + LOGIT1(" %3d: Unknown, virtual", currentId) break; + } + } + else + { + switch ( (*iIapCache)[j].iServiceType ) + { + case EConnMonCacheServiceTypeCsd: + LOGIT1(" %3d: CSD", currentId) break; + case EConnMonCacheServiceTypeGprs: + LOGIT1(" %3d: GPRS", currentId) break; + case EConnMonCacheServiceTypeLan: + LOGIT1(" %3d: LAN", currentId) break; + case EConnMonCacheServiceTypeWlan: + LOGIT1(" %3d: WLAN", currentId) break; + default: + LOGIT1(" %3d: Unknown", currentId) break; + } + } + } + } + #endif // _DEBUG + + TBool availableSnapsChanged = UpdateAvailableSnaps(); + + // Print available SNAP IDs to log + #ifdef _DEBUG + TUint lastSnapId( 0 ); + for ( TInt k = 0; k < iSnapCache->Count(); k++ ) + { + TUint currentId = (*iSnapCache)[k].iId; + if ( currentId != lastSnapId ) + { + lastSnapId = currentId; + if ( (*iSnapCache)[k].iAvailability == EConnMonAvailabilityAvailable ) + { + LOGIT1(" %4d", currentId) + } + } + } + LOGIT(".") + #endif // _DEBUG + + if ( aCanSendEvents ) + { + if ( availableIapsChanged ) + { + LOGIT("RefreshAvailabilityInfo: sending IAP availability event") + SendIapAvailabilityEvent(); + } + if ( availableSnapsChanged ) + { + LOGIT("RefreshAvailabilityInfo: sending SNAP availability event") + SendSnapAvailabilityEvent(); + } + } + + LOGEXITFN("CConnMonCommsDatCache::RefreshAvailabilityInfo()") + } + +// --------------------------------------------------------------------------- +// Set as available all IAPs which correspond to the given bearer ID +// (converted to service type). +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::SetAvailableIapsWithBearerId( const TUint aBearerId ) + { + //LOGENTRFN("CConnMonCommsDatCache::SetAvailableIapsWithBearerId()") + TInt err( KErrNone ); + + TUint serviceType; + err = ConvertBearerIdToServiceType( aBearerId, serviceType ); + + if ( !err ) + { + const TInt iapCount = iIapCache->Count(); + for ( TInt i = 0; i < iapCount; i++ ) + { + if ( (*iIapCache)[i].iServiceType == serviceType ) + { + (*iIapCache)[i].iAvailability = EConnMonAvailabilityAvailable; + } + } + } + + //LOGEXITFN("CConnMonCommsDatCache::SetAvailableIapsWithBearerId()") + } + +// --------------------------------------------------------------------------- +// Set as available the IAP with matching ID. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::SetAvailableIapWithId( const TUint aId ) + { + //LOGENTRFN("CConnMonCommsDatCache::SetAvailableIapWithId()") + + TInt index = iIapCache->FindInOrder( aId, TConnMonIapEntry::FindCompare ); + if ( index >= 0) + { + (*iIapCache)[index].iAvailability = EConnMonAvailabilityAvailable; + } + + //LOGEXITFN("CConnMonCommsDatCache::SetAvailableIapWithId()") + } + +// --------------------------------------------------------------------------- +// Get available IAP IDs for the requested bearer ID. IAP availability is +// re-solved first. +// Maximum number of IAP IDs is limited by KConnMonMaxIAPCount. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::GetAvailableIaps( + const TUint aBearerId, + TConnMonIapInfo& aIapInfo ) + { + LOGENTRFN("CConnMonCommsDatCache::GetAvailableIaps()") + TInt err( KErrNone ); + + TBool availabilityEventsEnabled( EFalse ); + if ( ( aBearerId == EBearerIdAll ) || ( aBearerId == EBearerIdVirtualVPN ) ) + { + // If WLAN background scanning is on, and client is asking IAP + // availability for all- or virtual IAPs, send IAP availability changed + // events if any changes detected. + TRAPD( traperr, availabilityEventsEnabled = IsWlanBackgroundScanningEnabledL() ); + if ( traperr ) + { + // If error here, continue as WLAN background scanning is disabled. + availabilityEventsEnabled = EFalse; + LOGIT1("ERROR, WLAN background scan discovery failed with <%d>", traperr) + } + } + + RefreshAvailabilityInfo( availabilityEventsEnabled ); + + TInt iapCount( 0 ); + TUint bearerType( 0 ); + TUint serviceType( 0 ); + TBool done( EFalse ); + + switch ( aBearerId ) + { + case EBearerIdAll: + { + iapCount = iIapIdCache.Count(); + if ( iapCount > KConnMonMaxIAPCount ) + { + iapCount = KConnMonMaxIAPCount; + } + aIapInfo.iCount = iapCount; + for ( TInt i = 0; i < iapCount; i++ ) + { + aIapInfo.iIap[i].iIapId = iIapIdCache[i]; + } + done = ETrue; + } + break; + case EBearerIdGPRS: + case EBearerIdWCDMA: + serviceType = EConnMonCacheServiceTypeGprs; + break; + case EBearerIdWLAN: + serviceType = EConnMonCacheServiceTypeWlan; + break; + case EBearerIdCSD: + case EBearerIdWcdmaCSD: + serviceType = EConnMonCacheServiceTypeCsd; + break; + case EBearerIdVirtualVPN: + bearerType = EConnMonCacheBearerTypeVirtual; + break; + case EBearerIdLAN: + serviceType = EConnMonCacheServiceTypeLan; + break; + default: + err = KErrArgument; + done = ETrue; + break; + } + + if ( !done ) + { + TInt totalCount = iIapCache->Count(); + for ( TInt i = 0; i < totalCount && iapCount < KConnMonMaxIAPCount; i++ ) + { + if ( serviceType ) + { + if ( (*iIapCache)[i].iAvailability == EConnMonAvailabilityAvailable && + (*iIapCache)[i].iServiceType == serviceType ) + { + aIapInfo.iIap[iapCount].iIapId = (*iIapCache)[i].iId; + iapCount++; + } + } + else if ( bearerType ) + { + if ( (*iIapCache)[i].iAvailability == EConnMonAvailabilityAvailable && + (*iIapCache)[i].iBearerType == bearerType ) + { + aIapInfo.iIap[iapCount].iIapId = (*iIapCache)[i].iId; + iapCount++; + } + } + } + aIapInfo.iCount = iapCount; + } + + LOGEXITFN1("CConnMonCommsDatCache::GetAvailableIaps()", err) + return err; + } + +// --------------------------------------------------------------------------- +// Get available SNAP IDs. SNAP availability is re-solved first. +// Maximum number of SNAP IDs is limited by KConnMonMaxSNAPsCount. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::GetAvailableSnaps( TConnMonSNAPInfo& aSnapInfo ) + { + LOGENTRFN("CConnMonCommsDatCache::GetAvailableSnaps()") + + TBool availabilityEventsEnabled( EFalse ); + // If WLAN background scanning is on, and client is asking SNAP + // availability, send SNAP availability changed events if any changes + // detected. + TRAPD( traperr, availabilityEventsEnabled = IsWlanBackgroundScanningEnabledL() ); + if ( traperr ) + { + // If error here, continue as WLAN background scanning is disabled. + availabilityEventsEnabled = EFalse; + LOGIT1("ERROR, WLAN background scan discovery failed: <%d>", traperr) + } + + RefreshAvailabilityInfo( availabilityEventsEnabled ); + + TInt snapCount = iSnapIdCache.Count(); + if ( snapCount > KConnMonMaxSNAPsCount ) + { + snapCount = KConnMonMaxSNAPsCount; + } + aSnapInfo.iCount = snapCount; + for ( TInt i = 0; i < snapCount; i++ ) + { + aSnapInfo.iSNAP[i].iSNAPId = iSnapIdCache[i]; + } + + LOGEXITFN("CConnMonCommsDatCache::GetAvailableSnaps()") + } + +// --------------------------------------------------------------------------- +// Get available SNAP IDs. SNAP availability is re-solved first. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::GetAvailableSnaps( RArray& aSnapIds ) + { + LOGENTRFN("CConnMonCommsDatCache::GetAvailableSnaps()") + + TBool availabilityEventsEnabled( EFalse ); + // If WLAN background scanning is on, and client is asking SNAP + // availability, send SNAP availability changed events if any changes + // detected. + TRAPD( traperr, availabilityEventsEnabled = IsWlanBackgroundScanningEnabledL() ); + if ( traperr ) + { + // If error here, continue as WLAN background scanning is disabled. + availabilityEventsEnabled = EFalse; + LOGIT1("ERROR, WLAN background scan discovery failed: <%d>", traperr) + } + + RefreshAvailabilityInfo( availabilityEventsEnabled ); + + // Return KErrNoMemory only if RArray fails to allocate memory, KErrNone otherwise + TInt err( KErrNone ); + err = aSnapIds.Reserve( iSnapIdCache.Count() ); + if ( !err ) + { + for ( TInt i = 0; i < iSnapIdCache.Count(); i++ ) + { + aSnapIds.Append( TConnMonId( iSnapIdCache[i] ) ); + } + } + + LOGEXITFN1("CConnMonCommsDatCache::GetAvailableSnaps()", err) + return err; + } + +// --------------------------------------------------------------------------- +// Constructor +// --------------------------------------------------------------------------- +// +CConnMonCommsDatCache::CConnMonCommsDatCache() + { + //LOGENTRFN("CConnMonCommsDatCache::CConnMonCommsDatCache()") + //LOGEXITFN("CConnMonCommsDatCache::CConnMonCommsDatCache()") + } + +// --------------------------------------------------------------------------- +// 2nd phase constructor +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::ConstructL() + { + //LOGENTRFN("CConnMonCommsDatCache::ConstructL()") + + iIap = NULL; + iInitStatus = EConnMonCacheInitNotStarted; + iVirtualIapCount = 0; + iWlanSupportEnabled = EFalse; // Set in Init()-method + + iIapsChanged = EFalse; + iSnapsChanged = EFalse; + iVirtualIapsChanged = EFalse; + + iIapRecordTableId = KCDTIdIAPRecord; + iSnapRecordTableId = 0; // Read from CommsDat when needed for first time + iVirtualRecordTableId = 0; // Read from CommsDat when needed for first time + + iIapCache = new( ELeave ) RArray(); + iSnapCache = new( ELeave ) RArray(); + iVirtualIapCache = new( ELeave ) RArray(); + + //LOGEXITFN("CConnMonCommsDatCache::ConstructL()") + } + +// --------------------------------------------------------------------------- +// Reads all relevant CommsDat information to cache and initializes the SNAP +// and virtual IAP table IDs. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::InitCommsDatCacheL() + { + //LOGENTRFN("CConnMonCommsDatCache::InitCommsDatCacheL()") + + CMDBSession* db = CMDBSession::NewLC( CMDBSession::LatestVersion() ); + db->SetAttributeMask( ECDHidden | ECDProtectedWrite ); + + // Find out the table IDs for CCDDataMobilitySelectionPolicyRecord and + // CCDVirtualIAPNextLayerRecord, only need to do this once. + iVirtualRecordTableId = CCDVirtualIAPNextLayerRecord::TableIdL( *db ); + iSnapRecordTableId = CCDDataMobilitySelectionPolicyRecord::TableIdL( *db ); + + LOGIT("InitCommsDatCacheL: reading commsdat tables") + RefreshCommsDatIapCacheL( *db ); + RefreshCommsDatSnapCacheL( *db ); + RefreshCommsDatVirtualIapCacheL( *db ); + + CleanupStack::PopAndDestroy( db ); + + //LOGEXITFN("CConnMonCommsDatCache::InitCommsDatCacheL()") + } + +// --------------------------------------------------------------------------- +// Reads all IAP information from CommsDat and updates the cache if necessary. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::RefreshCommsDatIapCacheL( CMDBSession& aDb ) + { + LOGENTRFN("CConnMonCommsDatCache::RefreshCommsDatIapCacheL()") + + // Will only leave if device runs out of memory or LoadL fails on IAP + // record set. This will result in an empty IAP cache and thus no IAP + // will be reported available through ConnMon API. + + RArray currentWlanIapIds; + CleanupClosePushL( currentWlanIapIds ); + + RArray* currentIapData; + if ( iInitStatus == EConnMonCacheInitCompleted ) + { + // Array to read current CommsDat info into. + currentIapData = new( ELeave ) RArray; // Heap used by design + CleanupClosePushL( *currentIapData ); + } + else + { + // Init-phase, read current CommsDat info directly into cache array, + // since it is still empty. Then stop (don't send any events). + iWlanIapIdCache.Reset(); + currentIapData = iIapCache; + } + currentIapData->Reset(); + + ReadCommsDatIapTableL( aDb, *currentIapData, currentWlanIapIds ); + + if ( iInitStatus != EConnMonCacheInitCompleted ) + { + // This is Init pass. CommsDat has been read and stored in cache. return now. + // Note, currentIapData not in cleanup stack + + // If no WLAN, this will just be an empty array + DeepCopy( currentWlanIapIds, iWlanIapIdCache ); + CleanupStack::Pop( ¤tWlanIapIds ); + currentWlanIapIds.Close(); + + iIapsChanged = ETrue; + LOGEXITFN1("CConnMonCommsDatCache::RefreshCommsDatIapCache()", iIapsChanged) + return iIapsChanged; + } + + CleanupStack::Pop( currentIapData ); + iIapsChanged = EFalse; + + // WLAN IAPs are most likely to change. Check those first for changes. + if ( iWlanSupportEnabled ) + { + iIapsChanged = CompareSortedArrays( currentWlanIapIds, iWlanIapIdCache ); + if ( iIapsChanged ) + { + if ( iIap ) + { + iIap->EnableWlanScan(); // Important + } + DeepCopy( currentWlanIapIds, iWlanIapIdCache ); + } + } + CleanupStack::Pop( ¤tWlanIapIds ); + currentWlanIapIds.Close(); + + // If WLAN IAPs didn't change, check the rest of the IAPs for changes. + if ( !iIapsChanged ) + { + iIapsChanged = CompareSortedArrays( *currentIapData, *iIapCache ); + } + + // Delete the obsolete IAP cache table. Either the new table that was just + // read, or the old table if the new one is different. + if ( iIapsChanged ) + { + iIapCache->Close(); + delete iIapCache; + iIapCache = currentIapData; + LOGIT("RefreshCommsDatIapCacheL: updated IAP cache") + } + else + { + currentIapData->Close(); + delete currentIapData; + currentIapData = NULL; + LOGIT("RefreshCommsDatIapCacheL: IAP cache did not change") + } + + LOGEXITFN1("CConnMonCommsDatCache::RefreshCommsDatIapCacheL()", iIapsChanged) + return iIapsChanged; + } + +// --------------------------------------------------------------------------- +// Reads all IAP table information from CommsDat into an array. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::ReadCommsDatIapTableL( + CMDBSession& aDb, + RArray& aCurrentIapData, + RArray& aCurrentWlanIapIds ) + { + LOGENTRFN("CConnMonCommsDatCache::ReadCommsDatIapTableL()") + + // Explicitly build a TLinearOrder. Used as parameter to RArray::InsertInOrder(). + TLinearOrder iapEntryOrderingLogic( TConnMonIapEntry::Compare ); + + CMDBRecordSet* ptrIapRecordSet = new( ELeave ) + CMDBRecordSet( iIapRecordTableId ); + CleanupStack::PushL( ptrIapRecordSet ); + ptrIapRecordSet->LoadL( aDb ); + + // Check LAN bearer table for WLAN bearer entries and store results in array. + // This information is used to separate LAN and WLAN IAPs from each other. + RArray lanBearerTableCache; + CleanupClosePushL( lanBearerTableCache ); + TRAPD( leaveCode, ReadCommsDatLanBearerTableL( aDb, lanBearerTableCache ) ); + if ( leaveCode ) + { + LOGIT1("ERROR reading LAN bearer table, LEAVE with <%d>", leaveCode) + lanBearerTableCache.Reset(); + } + + iVirtualIapCount = 0; + TInt iapRecordCount( ptrIapRecordSet->iRecords.Count() ); + LOGIT1("ReadCommsDatIapTableL: IAP record count %d (commsdat)", iapRecordCount) + + TUint iapId( 0 ); + TUint bearerType( 0 ); + TUint serviceType( 0 ); + + for ( TInt i = 0; i < iapRecordCount; i++ ) + { + TRAP( leaveCode, ReadCommsDatIapEntryL( + (CCDIAPRecord*)ptrIapRecordSet->iRecords[i], + lanBearerTableCache, + bearerType, + serviceType ) ); + + if ( leaveCode ) + { + // Skip this IAP and continue with next one + LOGIT1("ERROR reading IAP entry, LEAVE with <%d>", leaveCode) + break; + } + + iapId = ptrIapRecordSet->iRecords[i]->RecordId(); + + if ( serviceType == EConnMonCacheServiceTypeWlan && iWlanSupportEnabled ) + { + // Add WLAN IAP ID to WLAN IAP cache + TInt err = aCurrentWlanIapIds.InsertInOrder( iapId ); + if ( err ) + { + LOGIT1("ERROR inserting WLAN IAP ID to WLAN cache <%d>", err) + serviceType = 0; + } + } + + // Unknown IAP or error while reading it + if ( !serviceType && !bearerType ) + { + LOGIT1("WARNING, unknown IAP in CommsDat IAP table with id %d", iapId) + iapId = 0; // ID to zero so this IAP will be ignored + } + + if ( iapId ) + { + // Adding IAP to cache + TConnMonIapEntry iapEntry( iapId, bearerType, serviceType ); + + TInt err = aCurrentIapData.InsertInOrder( iapEntry , iapEntryOrderingLogic ); + if ( err ) + { + LOGIT1("ERROR inserting IAP to current IAP data <%d>", err) + } + } + } + + CleanupStack::Pop( &lanBearerTableCache ); + lanBearerTableCache.Close(); + CleanupStack::PopAndDestroy( ptrIapRecordSet ); + LOGIT1("ReadCommsDatIapTableL: IAP record count %d (cache)", aCurrentIapData.Count()) + + LOGEXITFN("CConnMonCommsDatCache::ReadCommsDatIapTableL()") + } + +// --------------------------------------------------------------------------- +// Reads one record from IAP table and finds out the service and bearer types. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::ReadCommsDatIapEntryL( + CCDIAPRecord* aIapEntry, + RArray& aLanBearerTableCache, + TUint& aBearerType, + TUint& aServiceType ) + { + //LOGENTRFN("CConnMonCommsDatCache::ReadCommsDatIapEntryL()") + + aBearerType = 0; + aServiceType = 0; + TBuf bearerTypeName( aIapEntry->iBearerType.GetL() ); + TBuf serviceTypeName( aIapEntry->iServiceType.GetL() ); + + if ( serviceTypeName == TPtrC( KCDTypeNameOutgoingWCDMA ) || + serviceTypeName == TPtrC( KCDTypeNameIncomingWCDMA ) ) + { + aServiceType = EConnMonCacheServiceTypeGprs; // GPRS IAP + } + else if ( serviceTypeName == TPtrC( KCDTypeNameLANService ) ) + { + // LAN or WLAN IAP + TUint32 bearerId( aIapEntry->iBearer ); + if ( bearerTypeName == TPtrC( KCDTypeNameLANBearer ) && + HasWlanBearer( bearerId, aLanBearerTableCache ) ) + { + aServiceType = EConnMonCacheServiceTypeWlan; // WLAN IAP + } + else + { + aServiceType = EConnMonCacheServiceTypeLan; // LAN IAP + } + } + else if ( ( serviceTypeName == TPtrC( KCDTypeNameDialOutISP ) ) || + ( serviceTypeName == TPtrC( KCDTypeNameDialInISP ) ) ) + { + aServiceType = EConnMonCacheServiceTypeCsd; // CSD IAP + } + + if ( bearerTypeName == TPtrC( KCDTypeNameVirtualBearer ) ) + { + iVirtualIapCount++; + aBearerType = EConnMonCacheBearerTypeVirtual; // Virtual IAP + } + + //LOGEXITFN("CConnMonCommsDatCache::ReadCommsDatIapEntryL()") + } + +// --------------------------------------------------------------------------- +// Reads all records from the LAN bearer table and checks if they are WLAN +// bearer type. Results are stored in an array. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::ReadCommsDatLanBearerTableL( + CMDBSession& aDb, + RArray& aLanBearerTableCache ) + { + LOGENTRFN("CConnMonCommsDatCache::ReadCommsDatLanBearerTableL()") + + CMDBRecordSet* ptrLanBearerRecordSet = new( ELeave ) + CMDBRecordSet( KCDTIdLANBearerRecord ); + CleanupStack::PushL( ptrLanBearerRecordSet ); + ptrLanBearerRecordSet->LoadL( aDb ); + + TInt lanBearerRecordCount( ptrLanBearerRecordSet->iRecords.Count() ); + for ( TInt i = 0; i < lanBearerRecordCount; i++ ) + { + TLanBearerEntry lanBearerEntry; + lanBearerEntry.iId = ptrLanBearerRecordSet->iRecords[i]->RecordId(); + + TBuf bearerRecordName( + ( (CCDLANBearerRecord*)ptrLanBearerRecordSet->iRecords[i] )->iRecordName.GetL() ); + + if ( bearerRecordName == TPtrC( KWlanBearerRecordName ) ) + { + lanBearerEntry.iWlanBearer = ETrue; + } + else + { + lanBearerEntry.iWlanBearer = EFalse; + } + aLanBearerTableCache.Append( lanBearerEntry ); + } + CleanupStack::PopAndDestroy( ptrLanBearerRecordSet ); + LOGIT2("LAN bearer record count %d/%d", aLanBearerTableCache.Count(), lanBearerRecordCount) + + LOGEXITFN("CConnMonCommsDatCache::ReadCommsDatLanBearerTableL()") + } + +// --------------------------------------------------------------------------- +// Reads all SNAP information from CommsDat and updates the cache if necessary. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::RefreshCommsDatSnapCacheL( CMDBSession& aDb ) + { + LOGENTRFN("CConnMonCommsDatCache::RefreshCommsDatSnapCacheL()") + + RArray* currentSnapData; + if ( iInitStatus == EConnMonCacheInitCompleted ) + { + // Array to read current CommsDat info into. + currentSnapData = new( ELeave ) RArray; // Heap used by design + CleanupClosePushL( *currentSnapData ); + } + else + { + // Init phase. Read CommsDat and store to cache. Then stop. (no events) + currentSnapData = iSnapCache; // Cache is still empty at init-phase. + } + currentSnapData->Reset(); + + ReadCommsDatSnapTableL( aDb, *currentSnapData ); + + if ( iInitStatus != EConnMonCacheInitCompleted ) + { + // This is Init pass. CommsDat SNAPs have been read and stored in cache. return now. + // Note, currentSnapData not in cleanup stack + iSnapsChanged = ETrue; + LOGEXITFN1("CConnMonCommsDatCache::RefreshCommsDatSnapCache()", iSnapsChanged) + return iSnapsChanged; + } + + CleanupStack::Pop( currentSnapData ); + iSnapsChanged = CompareSortedArrays( *currentSnapData, *iSnapCache ); + + // Delete the obsolete SNAP cache table. Either the new table that was just + // read, or the old table if the new one is different. + if ( iSnapsChanged ) + { + iSnapCache->Close(); + delete iSnapCache; + iSnapCache = currentSnapData; + LOGIT("RefreshCommsDatSnapCacheL: updated SNAP cache") + } + else + { + currentSnapData->Close(); + delete currentSnapData; + currentSnapData = NULL; + } + + LOGEXITFN1("CConnMonCommsDatCache::RefreshCommsDatSnapCacheL()", iSnapsChanged) + return iSnapsChanged; + } + +// --------------------------------------------------------------------------- +// Reads all SNAP information from CommsDat to an array. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::ReadCommsDatSnapTableL( + CommsDat::CMDBSession& aDb, + RArray& aCurrentSnapData ) + { + LOGENTRFN("CConnMonCommsDatCache::ReadCommsDatSnapTableL()") + // Explicitly build a TLinearOrder. Used as parameter to RArray::InsertInOrder(). + TLinearOrder snapEntryOrderingLogic( TConnMonSnapEntry::Compare ); + + CMDBRecordSet* ptrSnapRecordSet = new( ELeave ) + CMDBRecordSet( iSnapRecordTableId ); + CleanupStack::PushL( ptrSnapRecordSet ); + + CCDDataMobilitySelectionPolicyRecord* ptrSnapRecord = new( ELeave ) + CCDDataMobilitySelectionPolicyRecord( iSnapRecordTableId ); + CleanupStack::PushL( ptrSnapRecord ); + + ptrSnapRecordSet->LoadL( aDb ); + TInt snapRecordCount( ptrSnapRecordSet->iRecords.Count() ); + LOGIT1("ReadCommsDatSnapTableL: SNAP record count %d (commsdat)", snapRecordCount) + + TUint snapId( 0 ); + TUint includedIapId( 0 ); + TUint embeddedSnapId( 0 ); + TInt tempSnapId( 0 ); + TInt tempEmbeddedSnapId( 0 ); + + for ( TInt i = 0; i < snapRecordCount; i++ ) + { + ptrSnapRecord->SetElementId( ptrSnapRecordSet->iRecords[i]->ElementId() ); + ptrSnapRecord->LoadL( aDb ); + + // SNAP ID records in CCDDataMobilitySelectionPolicyRecord-table were changed + // from record links to TInt type, as part of new CommsInfra changes. + tempSnapId = ptrSnapRecord->iSNAP; + if ( tempSnapId < 0 ) + { + tempSnapId = 0; + } + snapId = (TUint) tempSnapId; + + includedIapId = ( ptrSnapRecord->iIAP & KCDMaskShowRecordId ) >> KBitsInByte; + + tempEmbeddedSnapId = ptrSnapRecord->iEmbeddedSNAP; + if ( tempEmbeddedSnapId < 0 ) + { + tempEmbeddedSnapId = 0; + } + embeddedSnapId = (TUint) tempEmbeddedSnapId; + + // Empty SNAPs are not included in cache + if ( includedIapId || embeddedSnapId ) + { + TConnMonSnapEntry snapEntry( snapId, includedIapId, embeddedSnapId ); + TInt err = aCurrentSnapData.InsertInOrder( snapEntry , snapEntryOrderingLogic ); + if ( err ) + { + LOGIT1("ERROR inserting SNAP record to current SNAP data <%d>", err) + } + } + } + CleanupStack::PopAndDestroy( ptrSnapRecord ); + CleanupStack::PopAndDestroy( ptrSnapRecordSet ); + LOGIT1("ReadCommsDatSnapTableL: SNAP record count %d (cache)", aCurrentSnapData.Count()) + LOGEXITFN("CConnMonCommsDatCache::ReadCommsDatSnapTableL()") + } + +// --------------------------------------------------------------------------- +// Reads all virtual IAP link information from CommsDat and updates the cache +// if necessary. CommsDat is not read if IAP table did not contain any virtual +// IAPs. Returns ETrue if cache information was changed, EFalse otherwise. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::RefreshCommsDatVirtualIapCacheL( CMDBSession& aDb ) + { + LOGENTRFN("CConnMonCommsDatCache::RefreshCommsDatVirtualIapCacheL()") + + RArray* currentVirtualIapData; + if ( iInitStatus == EConnMonCacheInitCompleted ) + { + // Array to read current CommsDat info into. + currentVirtualIapData = new( ELeave ) RArray; // Heap used by design + CleanupClosePushL( *currentVirtualIapData ); + } + else + { + // Init-phase, read current CommsDat info directly into cache array, + // since it is still empty. Then stop (don't send any events.) + currentVirtualIapData = iVirtualIapCache; + } + currentVirtualIapData->Reset(); + + // If there is no virtual IAPs, there is no need to read virtual IAP link + // information, and virtual IAP cache will be left empty. + if ( iVirtualIapCount ) + { + TRAPD( leaveCode, ReadCommsDatVirtualIapTableL( aDb, *currentVirtualIapData ) ); + if ( leaveCode ) + { + LOGIT1("ERROR reading virtual IAP table, LEAVE with <%d>", leaveCode) + } + } + else + { + LOGIT("RefreshCommsDatVirtualIapCacheL: no virtual IAPs, skipping") + } + + if ( iInitStatus != EConnMonCacheInitCompleted ) + { + // This is Init pass. CommsDat has been read and stored in cache. return now. + // Note, currentVirtualIapData not in cleanup stack + iVirtualIapsChanged = ETrue; + LOGEXITFN1("CConnMonCommsDatCache::RefreshCommsDatVirtualIapCacheL()", iVirtualIapsChanged) + return iVirtualIapsChanged; + } + + CleanupStack::Pop( currentVirtualIapData ); + iVirtualIapsChanged = CompareSortedArrays( *currentVirtualIapData, *iVirtualIapCache ); + + // Delete the obsolete virtual IAP cache table. Either the new table that + // was just read, or the old table if the new one is different. + if ( iVirtualIapsChanged ) + { + iVirtualIapCache->Close(); + delete iVirtualIapCache; + iVirtualIapCache = currentVirtualIapData; + LOGIT("RefreshCommsDatVirtualIapCacheL: updated virtual IAP cache") + } + else + { + currentVirtualIapData->Close(); + delete currentVirtualIapData; + currentVirtualIapData = NULL; + } + + LOGEXITFN1("CConnMonCommsDatCache::RefreshCommsDatVirtualIapCacheL()", iVirtualIapsChanged) + return iVirtualIapsChanged; + } + +// --------------------------------------------------------------------------- +// Reads all virtual IAP link information from CommsDat to an array. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::ReadCommsDatVirtualIapTableL( + CommsDat::CMDBSession& aDb, + RArray& aCurrentVirtualIapData ) + { + LOGENTRFN("CConnMonCommsDatCache::ReadCommsDatVirtualIapTableL()") + + // Explicitly build a TLinearOrder. Used as parameter to RArray::InsertInOrder(). + TLinearOrder virtualEntryOrderingLogic( + TConnMonVirtualIapEntry::Compare ); + + CMDBRecordSet* ptrVirtualRecordSet = new( ELeave ) + CMDBRecordSet( iVirtualRecordTableId ); + CleanupStack::PushL( ptrVirtualRecordSet ); + + CCDVirtualIAPNextLayerRecord* ptrVirtualRecord = new( ELeave ) + CCDVirtualIAPNextLayerRecord( iVirtualRecordTableId ); + CleanupStack::PushL( ptrVirtualRecord ); + + // Load and loop through the records. + ptrVirtualRecordSet->LoadL( aDb ); + TInt virtualRecordCount( ptrVirtualRecordSet->iRecords.Count() ); + LOGIT1("ReadCommsDatVirtualIapTableL: virtual record count %d (commsdat)", virtualRecordCount) + + TUint iapId( 0 ); + TUint nextLayerSnap( 0 ); + TUint nextLayerIap( 0 ); + + for ( TInt i = 0; i < virtualRecordCount; i++ ) + { + ptrVirtualRecord->SetElementId( ptrVirtualRecordSet->iRecords[i]->ElementId() ); + ptrVirtualRecord->LoadL( aDb ); + + iapId = ptrVirtualRecord->iIAP; + nextLayerSnap = ptrVirtualRecord->iNextLayerSNAP; + nextLayerIap = ptrVirtualRecord->iNextLayerIAP; + + // Either iNextLayerSNAP or iNextLayerIAP must be NULL. Only 1 link. + if ( iapId && ( ( nextLayerSnap && !nextLayerIap ) || + ( nextLayerIap && !nextLayerSnap ) ) ) + { + TConnMonVirtualIapEntry virtualEntry( iapId, nextLayerIap, nextLayerSnap ); + TInt err = aCurrentVirtualIapData.InsertInOrder( + virtualEntry, + virtualEntryOrderingLogic ); + if ( err ) + { + LOGIT1("ERROR inserting virtual IAP link record to cache <%d>", err) + } + } + else + { + LOGIT2("WARNING, invalid virtual record, iap: %d, snap: %d", nextLayerIap, nextLayerSnap ) + } + } + CleanupStack::PopAndDestroy( ptrVirtualRecord ); + CleanupStack::PopAndDestroy( ptrVirtualRecordSet ); + + LOGIT1("ReadCommsDatVirtualIapTableL: virtual record count %d (cache)", aCurrentVirtualIapData.Count()) + LOGEXITFN("CConnMonCommsDatCache::ReadCommsDatVirtualIapTableL()") + } + +// --------------------------------------------------------------------------- +// Compares two sorted RArray arrays. Returns ETrue if the arrays are +// not identical. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::CompareSortedArrays( + const RArray& aFirstArray, + const RArray& aSecondArray ) + { + //LOGENTRFN("CConnMonCommsDatCache::CompareSortedArrays()") + TBool arraysDiffer( EFalse ); + + const TInt firstCount = aFirstArray.Count(); + if ( firstCount != aSecondArray.Count() ) + { + arraysDiffer = ETrue; + } + else + { + for ( TInt i = 0; i < firstCount; i++ ) + { + if ( aFirstArray[i] != aSecondArray[i] ) + { + arraysDiffer = ETrue; + break; // No need to continue + } + } + } + + //LOGEXITFN1("CConnMonCommsDatCache::CompareSortedArrays()", arraysDiffer) + return arraysDiffer; + } + +// --------------------------------------------------------------------------- +// Compares two sorted RArray arrays. Returns ETrue if the +// arrays are not identical. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::CompareSortedArrays( + const RArray& aFirstArray, + const RArray& aSecondArray ) + { + //LOGENTRFN("CConnMonCommsDatCache::CompareSortedArrays()") + TBool arraysDiffer( EFalse ); + + const TInt firstCount = aFirstArray.Count(); + if ( firstCount != aSecondArray.Count() ) + { + arraysDiffer = ETrue; + } + else + { + for ( TInt i = 0; i < firstCount; i++ ) + { + if ( !TConnMonIapEntry::Match( aFirstArray[i], aSecondArray[i] ) ) + { + arraysDiffer = ETrue; + break; // No need to continue + } + } + } + + //LOGEXITFN1("CConnMonCommsDatCache::CompareSortedArrays()", arraysDiffer) + return arraysDiffer; + } + +// --------------------------------------------------------------------------- +// Compares two sorted RArray arrays. Returns ETrue if the +// arrays are not identical. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::CompareSortedArrays( + const RArray& aFirstArray, + const RArray& aSecondArray ) + { + //LOGENTRFN("CConnMonCommsDatCache::CompareSortedArrays()") + TBool arraysDiffer( EFalse ); + + const TInt firstCount = aFirstArray.Count(); + if ( firstCount != aSecondArray.Count() ) + { + arraysDiffer = ETrue; + } + else + { + for ( TInt i = 0; i < firstCount; i++ ) + { + if ( !TConnMonSnapEntry::Match( aFirstArray[i], aSecondArray[i] ) ) + { + arraysDiffer = ETrue; + break; // No need to continue + } + } + } + + //LOGEXITFN1("CConnMonCommsDatCache::CompareSortedArrays()", arraysDiffer) + return arraysDiffer; + } + +// --------------------------------------------------------------------------- +// Compares two sorted RArray arrays. Returns ETrue +// if the arrays are not identical. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::CompareSortedArrays( + const RArray& aFirstArray, + const RArray& aSecondArray ) + { + //LOGENTRFN("CConnMonCommsDatCache::CompareSortedArrays()") + TBool arraysDiffer( EFalse ); + + const TInt firstCount = aFirstArray.Count(); + if ( firstCount != aSecondArray.Count() ) + { + arraysDiffer = ETrue; + } + else + { + for ( TInt i = 0; i < firstCount; i++ ) + { + if ( !TConnMonVirtualIapEntry::Match( aFirstArray[i], aSecondArray[i] ) ) + { + arraysDiffer = ETrue; + break; // No need to continue + } + } + } + + //LOGEXITFN1("CConnMonCommsDatCache::CompareSortedArrays()", arraysDiffer) + return arraysDiffer; + } + +// --------------------------------------------------------------------------- +// Copy new data into a RArray array. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::DeepCopy( + const RArray& aSourceArray, + RArray& aTargetArray ) + { + //LOGENTRFN("CConnMonCommsDatCache::DeepCopy()") + + const TInt count = aSourceArray.Count(); + aTargetArray.Reset(); + TInt err = aTargetArray.Reserve( count ); + if ( KErrNone == err ) + { + for ( TInt i = 0; i < count; i++ ) + { + aTargetArray.Append( aSourceArray[i] ); + } + } + + //LOGEXITFN("CConnMonCommsDatCache::DeepCopy()") + } + +// --------------------------------------------------------------------------- +// Updates the index links for SNAPs and virtual IAPs. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::UpdateSnapAndVirtualIapLinks() + { + LOGENTRFN("CConnMonCommsDatCache::UpdateSnapAndVirtualIapLinks()") + + TInt count = iSnapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + TConnMonSnapEntry* pSnap = &(*iSnapCache)[i]; + if ( pSnap->iNextLayerIapId ) + { + pSnap->iNextLayerIndex = FindIapIndex( pSnap->iNextLayerIapId ); + } + else if ( pSnap->iNextLayerSnapId ) + { + pSnap->iNextLayerIndex = FindSnapIndex( pSnap->iNextLayerSnapId ); + } + } + + count = iIapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + TConnMonIapEntry* pIap = &(*iIapCache)[i]; + // Only virtual IAPs can have links + if ( pIap->iBearerType == EConnMonCacheBearerTypeVirtual ) + { + TInt index = iVirtualIapCache->FindInOrder( + pIap->iId, + TConnMonVirtualIapEntry::FindCompare ); + + if ( index < 0) + { + pIap->iNextLayerIapId = 0; + pIap->iNextLayerSnapId = 0; + pIap->iNextLayerIndex = KErrNotFound; + } + else + { + pIap->iNextLayerIapId = (*iVirtualIapCache)[index].iNextLayerIapId; + pIap->iNextLayerSnapId = (*iVirtualIapCache)[index].iNextLayerSnapId; + + // Either iNextLayerIapId or iNextLayerSnapId is 0. (already checked) + // Link to SNAP is more likely than link to IAP + if ( pIap->iNextLayerSnapId ) + { + // Returns KErrNotFound if not found + pIap->iNextLayerIndex = FindSnapIndex( pIap->iNextLayerSnapId ); + } + else if ( pIap->iNextLayerIapId ) + { + // Returns KErrNotFound if not found + pIap->iNextLayerIndex = FindIapIndex( pIap->iNextLayerIapId ); + } + } + } + } + + LOGEXITFN("CConnMonCommsDatCache::UpdateSnapAndVirtualIapLinks()") + } + +// --------------------------------------------------------------------------- +// Resets the availability status for all SNAPs and IAPs. SNAPs and virtual +// IAPs are set to unknown, because their availability depends on real IAPs +// and needs to be solved using recursive algorithms. Real IAPs are set to +// unavailable. The next step should be to find the real IAPs that are +// available. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::ResetAllAvailabilityInfo() + { + //LOGENTRFN("CConnMonCommsDatCache::ResetAllAvailabilityInfo()") + + TInt count = iIapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + if ( (*iIapCache)[i].iBearerType == EConnMonCacheBearerTypeVirtual ) + { + (*iIapCache)[i].iAvailability = EConnMonAvailabilityUnknown; + } + else + { + (*iIapCache)[i].iAvailability = EConnMonAvailabilityUnavailable; + } + } + + count = iSnapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + (*iSnapCache)[i].iAvailability = EConnMonAvailabilityUnknown; + } + + //LOGEXITFN("CConnMonCommsDatCache::ResetAllAvailabilityInfo()") + } + +// --------------------------------------------------------------------------- +// Solve SNAP and virtual IAP availability. The results depend on real IAP +// availability, so those need to be set when this method is called. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::SolveSnapAndVirtualIapAvailability() + { + LOGENTRFN("CConnMonCommsDatCache::SolveSnapAndVirtualIapAvailability()") + + TInt count = iSnapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + // Check SNAP availability recursively at index i + CheckSnapAvailability( i ); + } + + count = iIapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + if ( (*iIapCache)[i].iBearerType == EConnMonCacheBearerTypeVirtual ) + { + // Check IAP availability recursively at index i + CheckIapAvailability( i ); + } + } + + LOGEXITFN("CConnMonCommsDatCache::SolveSnapAndVirtualIapAvailability()") + } + +// --------------------------------------------------------------------------- +// Create a EConnMonIapAvailabilityChange event and add it to the event +// queue to be sent to clients. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::SendIapAvailabilityEvent() + { + LOGENTRFN("CConnMonCommsDatCache::SendIapAvailabilityEvent()") + TInt err( KErrNone ); + + TInt iapCount = iIapIdCache.Count(); + if ( iapCount > KConnMonMaxIAPCount ) + { + // If too many IAPs available, clip the extras away from event. + LOGIT1("WARNING, too many IAPs (%d), all did not fit into event", iapCount) + iapCount = KConnMonMaxIAPCount; + } + + TEventInfo info; + info.Reset(); + info.iEventType = EConnMonIapAvailabilityChange; + info.iConnectionId = EBearerIdAll; + info.iData = iapCount; + + // Create event data area. Leave left out intentionally, check for NULL instead + TConnMonIapInfo* eventIaps = new TConnMonIapInfo; // No (ELeave) + if ( !eventIaps ) + { + err = KErrNoMemory; + } + else + { + eventIaps->iCount = iapCount; + TInt i = 0; + for ( ; i < iapCount; i++ ) + { + eventIaps->iIap[i].iIapId = iIapIdCache[i]; + } + for ( ; i < KConnMonMaxIAPCount; i++ ) + { + eventIaps->iIap[i].iIapId = 0; + } + + // EventQueue will finally destroy the memory area pointed by eventIaps. + // However, if all the clients can't receive the event right away the + // event queue will keep it until the last client has received it. + iServer->EventQueue()->Add( + info, + reinterpret_cast( eventIaps ), + sizeof( TConnMonIapInfo ) ); + } + + LOGEXITFN1("CConnMonCommsDatCache::SendIapAvailabilityEvent()", err) + return err; + } + +// --------------------------------------------------------------------------- +// Create a EConnMonSNAPsAvailabilityChange event and add it to the event +// queue to be sent to clients. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::SendSnapAvailabilityEvent() + { + LOGENTRFN("CConnMonCommsDatCache::SendSnapAvailabilityEvent()") + TInt err( KErrNone ); + + TInt snapCount = iSnapIdCache.Count(); + + TEventInfo info; + info.Reset(); + info.iEventType = EConnMonSNAPsAvailabilityChange; + info.iConnectionId = EBearerIdAll; + info.iData = snapCount; // Total amount of available SNAPs + + if ( snapCount > KConnMonMaxSNAPsCount ) + { + // If too many SNAPs available, clip the extras away from event. + LOGIT1("WARNING, too many SNAPs (%d), all did not fit into event", snapCount) + snapCount = KConnMonMaxSNAPsCount; + } + + // Create event data area. Leave left out intentionally, check for NULL instead + TConnMonSNAPInfo* eventSnaps = new TConnMonSNAPInfo; // No (ELeave) + if ( !eventSnaps ) + { + err = KErrNoMemory; + } + else + { + eventSnaps->iCount = snapCount; + TInt i = 0; + for ( ; i < snapCount; i++ ) + { + eventSnaps->iSNAP[i].iSNAPId = iSnapIdCache[i]; + } + for ( ; i < KConnMonMaxSNAPsCount; i++ ) + { + eventSnaps->iSNAP[i].iSNAPId = 0; + } + + // EventQueue will finally destroy the memory area pointed by eventSnaps. + // However, if all the clients can't receive the event right away the + // event queue will keep it until the last client has received it. + iServer->EventQueue()->Add( + info, + reinterpret_cast( eventSnaps ), + sizeof( TConnMonSNAPInfo ) ); + } + + LOGEXITFN1("CConnMonCommsDatCache::SendSnapAvailabilityEvent()", err) + return err; + } + +// --------------------------------------------------------------------------- +// Finds the index in cache for IAP with id aId. Returns KErrNotFound (-1) if +// no match is found. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::FindIapIndex( const TUint aId ) + { + TInt index = iIapCache->FindInOrder( aId, TConnMonIapEntry::FindCompare ); + return index; + } + +// --------------------------------------------------------------------------- +// Finds the first index in cache for SNAP with ID aId. Returns KErrNotFound +// (-1) if no match is found. +// The SNAP cache is sorted by ID, so the first index is found by traversing +// decrementally from the initial index returned by RArray's FindInOrder. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::FindSnapIndex( const TUint aId ) + { + TInt index = iSnapCache->FindInOrder( aId, TConnMonSnapEntry::FindCompare ); + for ( ; index > 0; index-- ) + { + if ( (*iSnapCache)[index-1].iId != aId ) + { + return index; + } + } + return index; + } + +// --------------------------------------------------------------------------- +// Takes a SNAP cache index and reads the ID from that entry. Then adjusts the +// availability for each cache entry related to that ID. +// --------------------------------------------------------------------------- +// +void CConnMonCommsDatCache::SetSnapAvailabilityAtIndex( TUint aIndex, TInt aAvailability ) + { + //LOGENTRFN("CConnMonCommsDatCache::SetSnapAvailabilityAtIndex()") + + TUint id = (*iSnapCache)[aIndex].iId; + (*iSnapCache)[aIndex].iAvailability = aAvailability; + + TInt count = iSnapCache->Count(); + for ( TInt i = aIndex+1; i < count; i++ ) + { + if ( (*iSnapCache)[i].iId != id ) + { + return; + } + (*iSnapCache)[i].iAvailability = aAvailability; + } + + //LOGEXITFN("CConnMonCommsDatCache::SetSnapAvailabilityAtIndex()") + } + +// --------------------------------------------------------------------------- +// Check IAP availability by index. In case of virtual IAP, keeps checking +// recursively until something is found available or all link chains are +// checked. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::CheckIapAvailability( TUint aIndex ) + { + TConnMonIapEntry* pIap = &(*iIapCache)[aIndex]; + TInt currentAvailability = pIap->iAvailability; + switch ( currentAvailability ) + { + // Real IAPs should have availability status of either available or unavailable at this + // point. Unprocessed virtual IAPs and SNAPs should have availability status unknown. + // + case EConnMonAvailabilityProcessing: // Loop. Fallthrough intended + case EConnMonAvailabilityUnavailable: + return EConnMonAvailabilityUnavailable; + case EConnMonAvailabilityAvailable: + return EConnMonAvailabilityAvailable; + case EConnMonAvailabilityUnknown: + { + if ( pIap->iNextLayerIndex >= 0 ) + { + // Set availability status to processing (to detect/prevent loops) + pIap->iAvailability = EConnMonAvailabilityProcessing; + if ( pIap->iNextLayerSnapId ) + { + pIap->iAvailability = CheckSnapAvailability( pIap->iNextLayerIndex ); + } + else + { + pIap->iAvailability = CheckIapAvailability( pIap->iNextLayerIndex ); + } + } + else + { + // Virtual IAP that does not point anywhere + pIap->iAvailability = EConnMonAvailabilityUnavailable; + } + } + break; + default: + LOGIT1("ERROR, IAP entry contained invalid availability value: %d", currentAvailability) + return EConnMonAvailabilityUnavailable; + } + return pIap->iAvailability; + } + +// --------------------------------------------------------------------------- +// Check SNAP availability by index. Keeps checking recursively until something +// is found available inside or all contents of this SNAP have are checked. +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::CheckSnapAvailability( TUint aIndex ) + { + TInt currentAvailability = (*iSnapCache)[aIndex].iAvailability; + switch ( currentAvailability ) + { + case EConnMonAvailabilityProcessing: // Loop. Fallthrough intended + case EConnMonAvailabilityUnavailable: + return EConnMonAvailabilityUnavailable; + case EConnMonAvailabilityAvailable: + return EConnMonAvailabilityAvailable; + case EConnMonAvailabilityUnknown: + { + // Set availability status to processing (to detect/prevent loops) + SetSnapAvailabilityAtIndex( aIndex, EConnMonAvailabilityProcessing ); + + const TUint id = (*iSnapCache)[aIndex].iId; + const TInt count = iSnapCache->Count(); + + currentAvailability = EConnMonAvailabilityUnavailable; + for ( TInt i = aIndex; i < count; i++ ) + { + if ( (*iSnapCache)[i].iId != id ) + { + // This line belongs to next SNAP, finish here + break; + } + TInt link = (*iSnapCache)[i].iNextLayerIndex; + if ( link >= 0 ) + { + if ( (*iSnapCache)[i].iNextLayerIapId ) + { + currentAvailability = CheckIapAvailability( link ); + } + else + { + currentAvailability = CheckSnapAvailability( link ); + } + } + if ( currentAvailability == EConnMonAvailabilityAvailable ) + { + // Something inside this SNAP is available, no need to continue + break; + } + } + // Set this SNAP as available (all lines in cache that belong to this SNAP) + SetSnapAvailabilityAtIndex( aIndex, currentAvailability ); + } + break; + default: + LOGIT("ERROR, SNAP entry contained invalid availability value") + return EConnMonAvailabilityUnavailable; + } + return currentAvailability; + } + +// --------------------------------------------------------------------------- +// Updates the internal list of available IAP IDs and returns ETrue if it has +// changed. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::UpdateAvailableIaps() + { + //LOGENTRFN("CConnMonCommsDatCache::UpdateAvailableIaps()") + + RArray currentIapIds; + + // Read available IAP IDs from IAP cache + const TInt count = iIapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + if ( (*iIapCache)[i].iAvailability == EConnMonAvailabilityAvailable ) + { + TInt err = currentIapIds.InsertInOrder( (*iIapCache)[i].iId ); + if ( KErrNone != err ) + { + LOGIT1("ERROR inserting IAP ID to available IAPs cache <%d>", err) + break; + } + } + } + + // Check for changes + TBool arrayChanged = CompareSortedArrays( currentIapIds, iIapIdCache ); + if ( arrayChanged ) + { + LOGIT1("Available IAP count: %d (changed)", currentIapIds.Count()) + DeepCopy( currentIapIds, iIapIdCache ); + } + else + { + LOGIT1("Available IAP count: %d", currentIapIds.Count()) + } + currentIapIds.Close(); + + //LOGEXITFN1("CConnMonCommsDatCache::UpdateAvailableIaps()", arrayChanged) + return arrayChanged; + } + +// --------------------------------------------------------------------------- +// Updates the internal list of available SNAP IDs and returns ETrue if it has +// changed. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::UpdateAvailableSnaps() + { + //LOGENTRFN("CConnMonCommsDatCache::UpdateAvailableSnaps()") + + TUint lastSnapId( 0 ); + RArray currentSnapIds; + + // Read available SNAP IDs from SNAP cache. + // If there is n items inside a SNAP, then SNAP cache will contain n entries for that SNAP + const TInt count = iSnapCache->Count(); + for ( TInt i = 0; i < count; i++ ) + { + TUint currentId = (*iSnapCache)[i].iId; + if ( currentId != lastSnapId ) + { + lastSnapId = currentId; + if ( (*iSnapCache)[i].iAvailability == EConnMonAvailabilityAvailable ) + { + TInt err = currentSnapIds.InsertInOrder( currentId ); + if ( KErrNone != err ) + { + LOGIT1("ERROR inserting SNAP ID to available SNAPs cache <%d>", err) + break; + } + } + } + } + + // Check for changes + TBool arrayChanged = CompareSortedArrays( currentSnapIds, iSnapIdCache ); + if ( arrayChanged ) + { + LOGIT1("Available SNAP count: %d (changed)", currentSnapIds.Count()) + DeepCopy( currentSnapIds, iSnapIdCache ); + } + else + { + LOGIT1("Available SNAP count: %d", currentSnapIds.Count()) + } + currentSnapIds.Close(); + + //LOGEXITFN1("CConnMonCommsDatCache::UpdateAvailableSnaps()", arrayChanged) + return arrayChanged; + } + +// --------------------------------------------------------------------------- +// Checks from 'LAN bearer table' array if given ID has a WLAN bearer +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::HasWlanBearer( + TUint32 aId, + RArray& aLanBearerTableCache ) + { + //LOGENTRFN("CConnMonCommsDatCache::HasWlanBearer()") + TBool wlanBearer( EFalse ); + + for ( TInt i = 0; i < aLanBearerTableCache.Count(); i++ ) + { + if ( aLanBearerTableCache[i].iId == aId ) + { + wlanBearer = aLanBearerTableCache[i].iWlanBearer; + break; + } + } + + //LOGEXITFN1("CConnMonCommsDatCache::HasWlanBearer()", wlanBearer) + return wlanBearer; + } + +// --------------------------------------------------------------------------- +// Convert a bearer ID to (cache internal) service type +// --------------------------------------------------------------------------- +// +TInt CConnMonCommsDatCache::ConvertBearerIdToServiceType( + const TUint aBearerId, + TUint& aServiceType ) + { + //LOGENTRFN("CConnMonCommsDatCache::ConvertBearerIdToServiceType()") + TInt err( KErrNone ); + + switch ( aBearerId ) + { + case EBearerIdGPRS: + case EBearerIdWCDMA: + aServiceType = EConnMonCacheServiceTypeGprs; + break; + case EBearerIdCSD: + aServiceType = EConnMonCacheServiceTypeCsd; + break; + case EBearerIdWLAN: + aServiceType = EConnMonCacheServiceTypeWlan; + break; + case EBearerIdLAN: + aServiceType = EConnMonCacheServiceTypeLan; + break; + default: + LOGIT1("WARNING, ConvertBearerIdToServiceType() called with bad bearerId: %d", aBearerId) + aServiceType = EConnMonCacheServiceTypeUnknown; + err = KErrNotFound; + } + + //LOGEXITFN1("CConnMonCommsDatCache::ConvertBearerIdToServiceType()", err) + return err; + } + +// --------------------------------------------------------------------------- +// Checks from CommsDat if WLAN background scans are enabled. +// --------------------------------------------------------------------------- +// +TBool CConnMonCommsDatCache::IsWlanBackgroundScanningEnabledL() + { + LOGENTRFN("CConnMonCommsDatCache::IsWlanBackgroundScanningEnabledL()") + + TBool bgScanEnabled( EFalse ); + CMDBSession* db = CMDBSession::NewLC( CMDBSession::LatestVersion() ); + + CCDWlanDeviceSettingsRecord* ptrWlanDevSettingsRecord = new( ELeave ) + CCDWlanDeviceSettingsRecord( CCDWlanDeviceSettingsRecord::TableIdL( *db ) ); + CleanupStack::PushL( ptrWlanDevSettingsRecord ); + + ptrWlanDevSettingsRecord->iWlanDeviceSettingsType = KWlanUserSettings; + if( ptrWlanDevSettingsRecord->FindL( *db ) ) + { + ptrWlanDevSettingsRecord->LoadL( *db ); + if ( ptrWlanDevSettingsRecord->iBgScanInterval > 0 ) + { + bgScanEnabled = ETrue; + LOGIT1("WLAN background scans are enabled, interval: %d", (TUint)ptrWlanDevSettingsRecord->iBgScanInterval) + } + } + CleanupStack::PopAndDestroy( ptrWlanDevSettingsRecord ); + CleanupStack::PopAndDestroy( db ); + + LOGEXITFN1("CConnMonCommsDatCache::IsWlanBackgroundScanningEnabledL()", bgScanEnabled) + return bgScanEnabled; + } + +// End-of-file