tcpiputils/dnd/src/cache.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dnd/src/cache.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,263 @@
+// Copyright (c) 2004-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:
+// cache.cpp - the record cache
+//
+
+// This file contains the implementations of the CDndCache object.
+#include "engine.h"
+#include "node.h"
+#include "cache.h"
+#include <networking/dnd_err.h>
+#include "inet6log.h"
+
+// Cache root node for a specific name space
+class CDndNameSpace : public CDndNode
+	{
+public:
+	CDndNameSpace(TUint32 aNameSpaceId) : CDndNode(NULL, 0, _L8("")), iNameSpaceId(aNameSpaceId), iState(1) {}
+	~CDndNameSpace();
+	const TUint32 iNameSpaceId;	//< The name space ID
+	TInt iState;				//< Address state (initially = 1)
+	TInetAddr iAddr;			//< Server Address and port (if any)
+	CDndNameSpace *iNext;		//< Next name space root
+	};
+
+/**
+// The destructor has really nothing functional to do.
+// The precondition for destruct is that ALL nodes and
+// records under the root node have already been destroyed.
+*/
+CDndNameSpace::~CDndNameSpace()
+	{
+	ASSERT(IsEmpty());
+	}
+
+
+// CDndCache::CDndCache
+// ********************
+CDndCache::CDndCache()
+	{}
+
+
+// CDndCache::ContstructL
+// **********************
+void CDndCache::ConstructL()
+	{
+	LOG(Log::Printf(_L("CDndCache::ConstructL() size=%d\r\n"), (TInt)sizeof(*this)));
+	}
+
+
+// CDndCache::~CDndCache
+// *********************
+/**
+// Delete ALL records, and as a side effect all nodes
+// (except the roots are freed). And, then delete all
+// root nodes.
+//
+// If there are locked records, which prevent deletion
+// of all nodes, then cache destructor has been called
+// incorrectly! (=> ~CDndNameSpace() will panic)
+*/
+CDndCache::~CDndCache()
+	{
+	iRecordList.Cleanup(0);		// Delete all unlocked records
+	//
+	// Delete (now supposedly empty) root nodes
+	//
+	while (iRootList)
+		{
+		CDndNameSpace *ns = iRootList;
+		iRootList = iRootList->iNext;
+		delete ns;
+		}
+	}
+
+// CDndCache::Flush
+// ****************
+/**
+// Empty the cache.
+*/
+void CDndCache::Flush()
+	{
+	iRecordList.Cleanup(0);
+	}
+
+// CDndCache::GetServerAddress
+// ***************************
+/**
+// Get currently known server address for the name space.
+//
+// The address state is inially 1 (> 0). It is only changed by the
+// CDndCache::SetServerAddress .
+//
+// If the name-space does not have a root node, the root node
+// is created by this call (CDndCache::GetNameSpaceL).
+//
+// @param	aNameSpace	the name space id
+// @retval	aAddr		the server address currently associated with the name space
+// @returns	the state of the returned address as:
+//	@li	> 0, no address has been set
+//	@li	= 0, address set
+//	@li < 0, address set with error state, or
+//	@li	KErrNoMemory, if needed to create the root node and failed
+*/
+TInt CDndCache::GetServerAddress(const TUint32 aNameSpace, TInetAddr &aAddr)
+	{
+	CDndNameSpace *const ns = GetNameSpace(aNameSpace);
+	if (ns == NULL)
+		return KErrNoMemory;
+
+	aAddr = ns->iAddr;
+	return ns->iState;
+	}
+
+// CDndCache::SetServerAddress
+// ***************************
+/**
+// Set the server address/state for the name space.
+//
+// If the name-space does not have a root node, the root node
+// is created by this call (CDndCache::GetNameSpaceL).
+//
+// @param	aNameSpace	the name space id
+// @param	aAddr		the server address to be set
+// @param	aState		the state of the address
+*/
+void CDndCache::SetServerAddress(const TUint32 aNameSpace, const TInetAddr &aAddr, const TInt aState)
+	{
+	CDndNameSpace *const ns = GetNameSpace(aNameSpace);
+	if (ns != NULL)
+		{
+		ns->iAddr = aAddr;
+		ns->iState = aState;
+		}
+	}
+
+// CDndCache::GetNameSpace
+// ***********************
+/**
+// Locate the name space root or try to create it if not found.
+//
+// @param	aNameSpace	the name-space id
+// @returns	the name-space root or NULL, if not found and create
+//			failed.
+*/
+CDndNameSpace *CDndCache::GetNameSpace(const TUint32 aNameSpace)
+	{
+	CDndNameSpace *ns = iRootList;
+
+	// Does a request namespace already exist?
+	for ( ; ns != NULL; ns = ns->iNext)
+		if (ns->iNameSpaceId == aNameSpace)
+			return ns;
+
+	// Does not exist, a new namespace needed, create a new root
+	ns = new CDndNameSpace(aNameSpace);
+	if (ns)
+		{
+		ns->iNext = iRootList;
+		iRootList = ns;
+		}
+	return ns;
+	}
+
+
+// CDndCache::FindL
+// ****************
+/**
+// Find record from the cache.
+//
+// Finds the record from the cache which 
+// matches the name, type and class. If it has expired, it is invalidated
+// and returned. If no such record exists, one new record is inserted and
+// returned.
+//
+// If the name-space does not have a root node, the root node
+// is created by this call (CDndCache::GetNameSpaceL).
+//
+// @param	aNameSpace
+//		the name-space id. If ZERO, only search is performed
+//		across all currently existing name-spaces. No new
+//		state is created.
+// @param	aName
+//		the fully qualified domain-name which owns the record (dotted format)			
+// @param	aType
+//		the record type
+// @param	aClass
+//		the record class
+// @param	aReqTime
+//		the time of the request. This is used to detect records whose TTL
+//		is expired
+// @returns
+//		always a non-NULL pointer to the record matching (aNameSpace,aName,aType,aClass). The FindL
+//		will create the necessary node structures, if they do not exist before the call. If the
+//		record didn't exist before, the initial state of the new record is "Invalid".
+// @exception	KErrNoMemory
+//		the main potential reason for FindL to fail (not enough memory to create the objects)
+// @exception	KErrDndNoRecord
+//		can occur only when called with aNameSpace == 0, and the record does not exist.
+*/
+CDndRecord * CDndCache::FindL(const TUint32 aNameSpace, const TDesC8 &aName, const EDnsQType aType, const EDnsQClass aClass, 
+								const TTime &aReqTime)
+	{
+	CDndRecord *record = NULL;
+
+	if (aNameSpace == 0)
+		{
+		// If no name space is specified, then just search for match, never add record
+		for (CDndNameSpace *ns = iRootList; ; ns = ns->iNext)
+			{
+			if (ns == NULL)
+				User::Leave(KErrDndNoRecord);
+			record = ns->FindL(aName, FALSE, aType, aClass, iRecordList, aReqTime);
+			if (record)
+				break;
+			}
+		// record != NULL here, ALWAYS!
+		}
+	else
+		{
+		// When namespace is defined, always create the record and other necessary structures
+		// if neeeded.
+		//
+		iRecordList.Cleanup(KDndMaxRecords);
+		// Locate or create the name-space root
+		CDndNameSpace *const ns = GetNameSpace(aNameSpace);
+		if (ns == NULL)
+			User::Leave(KErrNoMemory);
+		// Locate (or create) the matching record
+		record = ns->FindL(aName, TRUE, aType, aClass, iRecordList, aReqTime);
+		// record != NULL here ALWAYS!
+		}
+
+	record->HitLRU();
+	return record;
+	}
+
+
+#ifdef _LOG
+// CDndCache::Dump
+// ***************
+/**
+// Print out the entire cache (for DEBUG only)
+*/
+void CDndCache::Dump(CDndEngine &aControl)
+	{
+	if (!iRootList)
+		aControl.ShowText(_L("No cache in the system"));
+	else
+		for (CDndNameSpace *ns = iRootList; ns != NULL; ns = ns->iNext)
+			ns->Print(aControl);
+	}
+#endif