networkprotocols/iphook/inhook6/src/dstcache.cpp
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // dstcache.cpp - Destination cache implementation
       
    15 // Destination cache implementation
       
    16 //
       
    17 
       
    18 
       
    19 
       
    20 /**
       
    21  @file dstcache.cpp
       
    22 */
       
    23 
       
    24 #include <in6_dstcache.h>
       
    25 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    26 #include <in6_dstcache_internal.h>
       
    27 #endif
       
    28 
       
    29 #ifdef NONSHARABLE_CLASS
       
    30 	NONSHARABLE_CLASS(CDestinationCache);
       
    31 #endif
       
    32 
       
    33 class CDestinationCache : public MDestinationCache, public CBase
       
    34 	{
       
    35 public:
       
    36 	CDestinationCache(TInt aKeyMode);
       
    37 //	~CDestinationCache();  // No explicit destructor needed, as far as I see
       
    38 	
       
    39 	void ConstructL();
       
    40 
       
    41 	virtual void StoreL(const TInetAddr &aAddr, TCacheInfo &aInfo);
       
    42 	
       
    43 	virtual const TCacheInfo *Find(const TInetAddr &aAddr);
       
    44 	
       
    45 	virtual void RemoveL(const TInetAddr &aAddr);
       
    46 	
       
    47 	virtual void SetL(const TInetAddr &aAddr, TUint aParIndex, TUint32 aValue);
       
    48 
       
    49 	virtual void Cleanup();
       
    50 	
       
    51 	virtual inline void RemoveAll()
       
    52 	{ iStorage.RemoveAll(); }
       
    53 	
       
    54 	virtual inline void SetLifetime(TUint aLifetime) { iLifetime = aLifetime; }
       
    55 
       
    56 	virtual inline void SetMaxSize(TUint aMaxSize) { iMaxSize = aMaxSize; }
       
    57 	
       
    58 	friend TBool IfIsExpired(const TCacheInfo &aCinfo, void *aCachePtr);
       
    59 	
       
    60 	virtual TBool Match(const TInetAddr& aAddrA, const TInetAddr& aAddrB) const;
       
    61 
       
    62 private:
       
    63 	TBool IsExpired(const TCacheInfo &aCinfo) const;
       
    64 
       
    65 	TCacheHash	iStorage;	//< Hash table that stores the destination cache entries
       
    66 	TUint		iLifetime;	//< Lifetime of a destination cache entry (seconds)
       
    67 	TUint		iMaxSize;	//< Maximum memory used for cache entries (bytes)
       
    68 	TUint		iMemUsed;	//< Current total memory used by cache entries
       
    69 
       
    70 	// Key Mode selected when instantiating this class
       
    71 	THashKeyIp6::TKeyMode	iKeyMode;
       
    72 	};
       
    73 
       
    74 
       
    75 EXPORT_C MDestinationCache *MDestinationCache::CreateDstCache(TInt aKeyMode)
       
    76 	{
       
    77 	CDestinationCache *dcache = new CDestinationCache(aKeyMode);
       
    78 	if (dcache)
       
    79 		{
       
    80 		TInt err = KErrNone;
       
    81 		// coverity[leave_without_push]
       
    82 		// if ConstructL() leaves, the leave code is trapped in "err" and proper cleanup is done by freeing the memory alocated to "dcache"
       
    83 		TRAP(err, dcache->ConstructL());
       
    84 		if (err != KErrNone)
       
    85 			{
       
    86 			delete dcache;
       
    87 			dcache = NULL;
       
    88 			}
       
    89 		}
       
    90 	return dcache;
       
    91 	}
       
    92 
       
    93 
       
    94 CDestinationCache::CDestinationCache(TInt aKeyMode) :	CBase(),
       
    95 														iStorage(KCacheHashSize),
       
    96 														iLifetime(KDstCacheLifetime),
       
    97 														iMaxSize(KDstCacheMaxSize)
       
    98 	{
       
    99 	switch (aKeyMode)
       
   100 		{
       
   101 	case 2:
       
   102 		iKeyMode = THashKeyIp6::EPerNet;
       
   103 		break;
       
   104 
       
   105 	default:
       
   106 		iKeyMode = THashKeyIp6::EPerHost;
       
   107 		break;
       
   108 		
       
   109 		// EPerIface not yet implemented		
       
   110 		}
       
   111 	}
       
   112 	
       
   113 	
       
   114 void CDestinationCache::ConstructL()
       
   115 	{
       
   116 	iStorage.ConstructL();
       
   117 	}
       
   118 
       
   119 
       
   120 void CDestinationCache::StoreL(const TInetAddr &aAddr, TCacheInfo &aInfo)
       
   121 	{
       
   122 	aInfo.iStoreTime.UniversalTime();
       
   123 	THashKeyIp6 k(iKeyMode, aAddr);
       
   124 	
       
   125 	// Check that hash size does not exceed the given limit.
       
   126 	// If it is about to do so, clean up expired entries and try again.
       
   127 	// If it still fails, StoreL fails.
       
   128 	if (iMemUsed >= iMaxSize)
       
   129 		{
       
   130 		Cleanup();  // This reduces iMemUsed if there was expired entries
       
   131 		if (iMemUsed >= iMaxSize)
       
   132 			{
       
   133 			User::Leave(KErrNoMemory);  // TODO: change error code
       
   134 			}
       
   135 		}
       
   136 	
       
   137 	// Check if there is a non-expired entry in the cache. If incoming aInfo has any
       
   138 	// non-null entries, they replace the earlier cache entries. Entries that were
       
   139 	// not updated with this call remain unmodified in the cache.
       
   140 	// However, the store time is refreshed.
       
   141 	TCacheInfo *oldent = iStorage.Find(k);
       
   142 	if (oldent && !IsExpired(*oldent))
       
   143 		{
       
   144 		for (TUint i = 0; i < KNumCacheMetrics; i++)
       
   145 			{
       
   146 			if (aInfo.iMetrics[i] != 0)
       
   147 				oldent->iMetrics[i] = aInfo.iMetrics[i];
       
   148 			}
       
   149 		oldent->iStoreTime.UniversalTime();
       
   150 
       
   151 		return;  // Hash-store method is not needed this time.
       
   152 		}
       
   153 	
       
   154 	TUint mem = iStorage.StoreL(k, aInfo);
       
   155 	iMemUsed += mem;
       
   156 	}
       
   157 	
       
   158 	
       
   159 void CDestinationCache::SetL(const TInetAddr &aAddr, TUint aParIndex, TUint32 aValue)
       
   160 	{
       
   161 	TCacheInfo *infoptr;
       
   162 
       
   163 	// Overwrite existing value if it exists, otherwise create a new entry in cache
       
   164 	THashKeyIp6 k(iKeyMode, aAddr);
       
   165 	infoptr = iStorage.Find(k);
       
   166 
       
   167 	if (infoptr && !IsExpired(*infoptr))
       
   168 		{
       
   169 		infoptr->iMetrics[aParIndex] = aValue;
       
   170 		infoptr->iStoreTime.UniversalTime();
       
   171 		}
       
   172 	else
       
   173 		{
       
   174 		TCacheInfo newinfo;
       
   175 		newinfo.ClearAll();
       
   176 		newinfo.iMetrics[aParIndex] = aValue;
       
   177 		StoreL(aAddr, newinfo);
       
   178 		}
       
   179 	}
       
   180 	
       
   181 
       
   182 const TCacheInfo *CDestinationCache::Find(const TInetAddr &aAddr)
       
   183 	{
       
   184 	THashKeyIp6 k(iKeyMode, aAddr);
       
   185 	TCacheInfo *cinfo = iStorage.Find(k);
       
   186 	
       
   187 	// Check whether the cache entry is recent enough. If not, return NULL.
       
   188 	// However, we don't delete an expired entry from cache. It remains as a placeholder
       
   189 	// for future equivalent entries.
       
   190 	if (!cinfo || IsExpired(*cinfo))
       
   191 		{
       
   192 		return NULL;
       
   193 		}
       
   194 	
       
   195 	return cinfo;
       
   196 	}
       
   197 	
       
   198 
       
   199 void CDestinationCache::RemoveL(const TInetAddr &aAddr)
       
   200 	{
       
   201 	THashKeyIp6 k(iKeyMode, aAddr);
       
   202 	TUint mem = iStorage.RemoveL(k);
       
   203 	iMemUsed -= mem;
       
   204 	}
       
   205 
       
   206 
       
   207 // Same as CDestinationCache::IsExpired(), but this is to be used with RemoveIf() call.
       
   208 TBool IfIsExpired(const TCacheInfo &aCinfo, void *aCachePtr)
       
   209 	{
       
   210 	if (!aCachePtr)
       
   211 		{
       
   212 		return EFalse;
       
   213 		}
       
   214 	return ((CDestinationCache *)aCachePtr)->IsExpired(aCinfo);
       
   215 	}
       
   216 
       
   217 
       
   218 void CDestinationCache::Cleanup()
       
   219 	{
       
   220 	iMemUsed -= iStorage.RemoveIf(IfIsExpired, this);
       
   221 	}
       
   222 
       
   223 
       
   224 TBool CDestinationCache::IsExpired(const TCacheInfo &aCinfo) const
       
   225 	{
       
   226 	TTime now;
       
   227 	TTimeIntervalSeconds secs;
       
   228 	
       
   229 	now.UniversalTime();
       
   230 	if (now.SecondsFrom(aCinfo.iStoreTime, secs) != KErrNone)
       
   231 		{
       
   232 		// Overflow or something. Consider it as expired entry.
       
   233 		return ETrue;
       
   234 		}
       
   235 	
       
   236 	if ((TUint)secs.Int() > iLifetime)
       
   237 		{
       
   238 		// Expired
       
   239 		return ETrue;
       
   240 		}
       
   241 	
       
   242 	return EFalse;
       
   243 	}
       
   244 	
       
   245 
       
   246 TBool CDestinationCache::Match(const TInetAddr& aAddrA, const TInetAddr& aAddrB) const
       
   247 	{
       
   248 	THashKeyIp6 ka(iKeyMode, aAddrA);
       
   249 	THashKeyIp6 kb(iKeyMode, aAddrB);
       
   250 	
       
   251 	return ka.IsEqual(kb);
       
   252 	}
       
   253 
       
   254 
       
   255 // --- THashTable methods ---
       
   256 
       
   257 template <class K, class V>
       
   258 THashTable<K,V>::THashTable(TUint aSize) : iTable(NULL), iSize(aSize)
       
   259 	{
       
   260 	}
       
   261 
       
   262 
       
   263 template <class K, class V>
       
   264 THashTable<K,V>::~THashTable()
       
   265 	{
       
   266 	RemoveAll();
       
   267 	delete [] iTable;
       
   268 	}
       
   269 
       
   270 
       
   271 template <class K, class V>
       
   272 void THashTable<K,V>::ConstructL()
       
   273 	{
       
   274 	iTable = new TChain<K,V>[iSize];
       
   275 	if (!iTable)
       
   276 		{
       
   277 		User::Leave(KErrNoMemory);
       
   278 		}
       
   279 	
       
   280 	for (TUint i = 0; i < iSize; i++)
       
   281 		{
       
   282 		iTable[i].iNext = NULL;
       
   283 		}
       
   284 	}
       
   285 	
       
   286 	
       
   287 template <class K, class V>
       
   288 TUint THashTable<K,V>::StoreL(MHashKey& aKey, V& aValue)
       
   289 	{	
       
   290 	if (!iTable)
       
   291 		{
       
   292 		User::Leave(KErrGeneral);
       
   293 		}
       
   294 
       
   295 	TUint memused = 0;
       
   296 	TInt idx = aKey.ToInt() % iSize;
       
   297 	TChain<K,V> *ptr = &iTable[idx], *newitem = NULL;
       
   298 	while (ptr->iNext)
       
   299 		{
       
   300 		if (ptr->iNext->iKey.IsEqual(aKey))
       
   301 			{
       
   302 			// The conventional mode would be:
       
   303 			//     User::Leave(KErrAlreadyExists)
       
   304 			// ...however, due to the lazy garbage collection mode adopted, we overwrite
       
   305 			// the existing entry
       
   306 			newitem = ptr->iNext;
       
   307 			break;
       
   308 			}
       
   309 		ptr = ptr->iNext;
       
   310 		}
       
   311 
       
   312 	// If the key wasn't stored earlier, allocate space for new data item.
       
   313 	// Allocations from heap is not always a very popular idea, but these events are
       
   314 	// expected to occur quite rarely.
       
   315 	if (!newitem)
       
   316 		{
       
   317 		newitem = new(ELeave) TChain<K,V>;
       
   318 
       
   319 		if (!newitem)
       
   320 			{
       
   321 			User::Leave(KErrNoMemory);
       
   322 			}
       
   323 			
       
   324 		newitem->iKey = *((K*) &aKey);
       
   325 		newitem->iNext = NULL;
       
   326 		ptr->iNext = newitem;
       
   327 		memused = sizeof(TChain<K,V>);
       
   328 		}
       
   329 		
       
   330 	newitem->iValue = aValue;
       
   331 	
       
   332 	/* Dynamically allocated memory newitem has been assigned to ptr->iNext and managed through the list.
       
   333 	So CleanupStack::PopAndDestroy() will deallocate that memory. But, Coverity has misinterpreted it an issue.*/
       
   334 	// coverity [SYMBIAN.CLEANUP STACK]
       
   335 	// coverity [memory_leak]
       
   336 	return memused;
       
   337 	}
       
   338 	
       
   339 	
       
   340 template <class K, class V>
       
   341 V* THashTable<K,V>::Find(MHashKey& aKey)
       
   342 	{
       
   343 	if (!iTable) return NULL;
       
   344 
       
   345 	TInt idx = aKey.ToInt() % iSize;
       
   346 	TChain<K,V> *ptr = &iTable[idx];
       
   347 	while (ptr->iNext)
       
   348 		{
       
   349 		if (ptr->iNext->iKey.IsEqual(aKey))
       
   350 			{
       
   351 			return &ptr->iNext->iValue;
       
   352 			}
       
   353 		ptr = ptr->iNext;
       
   354 		}
       
   355 		
       
   356 	// Not found
       
   357 	return NULL;
       
   358 	}
       
   359 	
       
   360 	
       
   361 template <class K, class V>
       
   362 TUint THashTable<K,V>::RemoveL(MHashKey& aKey)
       
   363 	{
       
   364 	if (!iTable)
       
   365 		{
       
   366 		User::Leave(KErrGeneral);
       
   367 		}
       
   368 
       
   369 	TInt idx = aKey.ToInt() % iSize;
       
   370 	TChain<K,V> *ptr = &iTable[idx];
       
   371 	while (ptr->iNext)
       
   372 		{
       
   373 		if (ptr->iNext->iKey.IsEqual(aKey))
       
   374 			{
       
   375 			TChain<K,V> *removed = ptr->iNext;
       
   376 			ptr->iNext = removed->iNext;
       
   377 			delete removed;
       
   378 			return sizeof(TChain<K,V>);
       
   379 			}
       
   380 		}
       
   381 		
       
   382 	// Key was not found
       
   383 	User::Leave(KErrNotFound);
       
   384 	return 0;
       
   385 	}
       
   386 	
       
   387 	
       
   388 template <class K, class V>
       
   389 TUint THashTable<K,V>::Length()
       
   390 	{
       
   391 	if (!iTable) return 0;
       
   392 
       
   393 	TUint length = 0;
       
   394 	
       
   395 	for (TInt idx = 0; idx < iSize; idx++)
       
   396 		{
       
   397 		TChain<K,V> *ptr = &iTable[idx];
       
   398 		while (ptr->iNext)
       
   399 			{
       
   400 			length++;
       
   401 			ptr = ptr->iNext;
       
   402 			}
       
   403 		}
       
   404 	return length;
       
   405 	}
       
   406 
       
   407 
       
   408 template <class K, class V>
       
   409 TUint THashTable<K,V>::RemoveIf(	TBool (*aRemoveCriteria)(const V&, void *),
       
   410 									void *aDataObject)
       
   411 	{
       
   412 	if (!iTable)
       
   413 		{
       
   414 		return 0;
       
   415 		}
       
   416 	
       
   417 	TUint memfreed = 0;
       
   418 	TChain<K,V> *ptr = NULL;
       
   419 	for (TUint idx = 0; idx < iSize; idx++)
       
   420 		{
       
   421 		ptr = &iTable[idx];
       
   422 		while (ptr->iNext)
       
   423 			{
       
   424 			if (aRemoveCriteria(ptr->iNext->iValue, aDataObject))
       
   425 				{
       
   426 				TChain<K,V> *removed = ptr->iNext;
       
   427 				ptr->iNext = removed->iNext;
       
   428 				delete removed;
       
   429 				memfreed += sizeof(TChain<K,V>);				
       
   430 				}
       
   431 			ptr = ptr->iNext;
       
   432 			}
       
   433 		}
       
   434 
       
   435 	return memfreed;
       
   436 	}
       
   437 
       
   438 
       
   439 template <class K, class V>
       
   440 void THashTable<K,V>::RemoveAll()
       
   441 	{
       
   442 	if (iTable != NULL)
       
   443 		{
       
   444 		TChain<K,V> *ptr = NULL, *last = NULL;
       
   445 		for (TUint i = 0; i < iSize; i++)
       
   446 			{
       
   447 			// Remember that the first chain entry in &iTable[i] does not contain data.
       
   448 			// The data items start from the linked entries.
       
   449 			ptr = &iTable[i];
       
   450 			while (ptr)
       
   451 				{
       
   452 				ptr = ptr->iNext;
       
   453 				if (last) delete last;
       
   454 				last = ptr;
       
   455 				}
       
   456 			}
       
   457 		}	
       
   458 	}
       
   459 
       
   460 	
       
   461 THashKeyIp6::THashKeyIp6(TKeyMode aKeyMode, const TInetAddr& aAddr)
       
   462 	{
       
   463 	// TODO: retrieve key mode, and assign only a prefix instead of full address.
       
   464 	// Simple prefix length is not enough, because I'd like to use the same cache for
       
   465 	// both IPv4 and IPv6
       
   466 	iKeyMode = aKeyMode;
       
   467 	iAddress = aAddr.Ip6Address();
       
   468 	iScopeId = aAddr.Scope();
       
   469 	}
       
   470 
       
   471 
       
   472 TUint THashKeyIp6::ToInt()
       
   473 	{
       
   474 	if (iKeyMode == EPerNet)
       
   475 		{
       
   476 		if (iAddress.IsV4Mapped())
       
   477 			{
       
   478 			// IPv4: Network is considered a /24
       
   479 			return iAddress.u.iAddr32[3] >> 8;
       
   480 			}
       
   481 		else
       
   482 			{
       
   483 			// IPv6: Network is considered a /64.
       
   484 			// Return the least significant 32 bits from the network part.
       
   485 			return iAddress.u.iAddr32[1];
       
   486 			}
       
   487 		}
       
   488 	else  // EPerHost and others (EPerIface not yet implemented)
       
   489 		{
       
   490 		// The least significant 32 bits is used as the int index
       
   491 		return iAddress.u.iAddr32[3];
       
   492 		}
       
   493 	}
       
   494 	
       
   495 	
       
   496 TBool THashKeyIp6::IsEqual(const MHashKey& aKey)
       
   497 	{
       
   498 	// casting is always risky business, but the user is required
       
   499 	// to use this method properly
       
   500 	const TIp6Addr addr2 = ((const THashKeyIp6&)aKey).Ip6Address();
       
   501 	
       
   502 	// If scope id is different, match will always fail
       
   503 	// (until per interface mode is implemented)
       
   504 	if (iScopeId != ((const THashKeyIp6&)aKey).ScopeId())
       
   505 		{
       
   506 		return EFalse;
       
   507 		}
       
   508 
       
   509 	if (iKeyMode == EPerNet)
       
   510 		{
       
   511 		TInt match = iAddress.Match(addr2);
       
   512 		if (iAddress.IsV4Mapped() && match >= 96 + 24)
       
   513 			{
       
   514 			return ETrue;
       
   515 			}
       
   516 		else if (match >= 64)
       
   517 			{
       
   518 			return ETrue;
       
   519 			}
       
   520 		return EFalse;
       
   521 		}
       
   522 	else  // EPerHost and others (EPerIface not yet implemented)
       
   523 		{
       
   524 		return iAddress.IsEqual(addr2);
       
   525 		}
       
   526 	}