tcpiputils/dnd/src/node.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dnd/src/node.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,260 @@
+// 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:
+// node.cpp - structures to hold node information
+// CDndNode object acts as a node in the tree that represents the cache for the DNS responses.
+// TDndNodeList is a linked list of CDndNode objects.
+//
+
+#include "node.h"
+#include "engine.h"
+#include <networking/dnd_err.h>
+#include "inet6log.h"
+
+const TInt CDndNode::iOffset = _FOFF(CDndNode, iDlink);
+
+// CDndNode::CDndNode
+// ******************
+CDndNode::CDndNode(CDndNode *const aParent, const TInt aLevel, const TNodeLabel &aLabel)
+: iParent(aParent), iLevel(aLevel), iLabel(aLabel)
+	{
+	}
+
+// CDndNode::~CDndNode
+// *******************
+CDndNode::~CDndNode()
+	{
+	//
+	// Node can NEVER be deleted, if it has children or records!
+	//
+	__ASSERT_ALWAYS(IsEmpty(), User::Panic(_L("DND"), 0));
+	}
+
+// CDndNode::Cleanup
+// *****************
+/**
+// Starting from current node, delete nodes in the path
+// if they have no records and no children.
+//
+// Maintain the "cache invariant": whenever control is outside
+// the cache implementation, the cache must not contain any
+// nodes that have no child nodes and no records (with exception
+// of the root nodes at level 0, iParent == NULL)
+*/
+void CDndNode::Cleanup()
+	{
+	CDndNode *current = this;
+	while (current->iParent && current->IsEmpty())
+		{
+		CDndNode *parent = current->iParent;
+		parent->DeleteNode(current);
+		current = parent;
+		}
+	}
+
+// CDndNode::DeleteNode
+// ********************
+void CDndNode::DeleteNode(CDndNode *const aNode)
+	{
+	iChildren.DeleteNode(aNode);
+	}
+
+
+// CDndNode::DeleteRecord
+// **********************
+/**
+// This method must not be called by anyone else except the
+// CDndRecord::Delete().
+//
+// The call will detach the record instance from this node,
+// deletes the record instance, and also activates the
+// cleanup, which deletes a path of nodes, if they have
+// no records and no children. 
+//
+// @param	aRecord
+//		specifies the record to be deleted. This record must
+//		exist and be owned by the node 
+*/
+void CDndNode::DeleteRecord(CDndRecord *const aRecord)
+	{
+	iRecordList.Delete(aRecord);
+	Cleanup();
+	}
+
+
+
+// CDndNode::FindL
+// ***************
+/**
+// Split the dotted name into components labels and locate the
+// node at the end of the path defined by those labels. The
+// search starts from the current node. If necessary, the path
+// is created (aFlag != 0).
+//
+// After the end node of the path is located (or created), a
+// matching record is located (or created).
+//
+// @param	aName	defines the domain name
+// @param	aFlag
+//		if value is FALSE, only search is performed and a NULL returned if node
+//		is not found. If value is TRUE, the necessary path and final node is
+//		created, if they don't exist yet.
+// @param	aType	the type of the record
+// @param	aClass	the class of the record
+// @param	aLRU	the LRU list into which the record will belong
+//					(only used if record is created by this call).
+// @param	aReqTime	the current time (of the query)
+// @returns	a pointer to the newly created record
+//	@li	NULL, if node does not exist (can only happen, if aFlag == 0!
+//	@li	non-NULL pointer to the record matching the aName, aClass and aType
+// @leave KErrNoMemory
+//		The function leaves for non-recoverable error (out of memory).
+//		Can occur only if aFlag != 0.
+// @leave KErrDndBadQuery
+//		The query name is not valid as DNS domain name.
+*/
+CDndRecord *CDndNode::FindL(const TDesC8 &aName, const TBool aFlag,
+							const EDnsQType aType, const EDnsQClass aClass,
+							TDndRecordLRU &aLRU, const TTime &aReqTime)
+	{
+	CDndNode *current = this;
+	TPtrC8 remaining(aName);
+
+	while (remaining.Length() > 0)
+		{
+		// extract the next name segment
+		TPtrC8 currentLabel;
+		TInt index = remaining.LocateReverse('.');
+		if (index == KErrNotFound)
+			{
+			currentLabel.Set(remaining);
+			index = 0;	// Desired node is reached
+			}
+		else
+			{
+			if (index <= 0)
+				User::Leave(KErrDndBadQuery);	// a name starting with "." is not valid
+			currentLabel.Set(remaining.Mid(index + 1));
+			}
+
+		if (currentLabel.Length() == 0)
+			User::Leave(KErrDndBadQuery);			// bad name, empty labels "foo..bar" not legal!
+		if (currentLabel.Length() > KDnsMaxLabel)	// this should be 63! (DNS hard limit)
+			User::Leave(KErrDndBadQuery);
+
+		CDndNode *node = current->iChildren.Find(currentLabel);
+
+		if (node == NULL)
+			{
+			if (!aFlag)
+				return NULL;	// Do not insert!
+			node = new CDndNode(current, current->iLevel + 1, currentLabel);
+			if (node == NULL)
+				{
+				current->Cleanup();
+				User::Leave(KErrNoMemory);
+				}
+			current->iChildren.AddNode(*node);
+			}
+		remaining.Set(remaining.Left(index));
+		current = node;
+		}
+
+	CDndRecord *record = current->iRecordList.Find(aType, aClass, aReqTime);
+	if (!aFlag || record != NULL)
+		return record;
+
+	//
+	// The looked record does not exist yet, create it here
+	//
+	record = new CDndRecord(aLRU, *current, aType, aClass);
+	if (record == NULL)
+		{
+		// This may invalidate 'this' pointer, so careful here!
+		current->Cleanup();
+		User::Leave(KErrNoMemory);
+		}
+	else
+		current->iRecordList.Add(*record);
+	return record;
+	}
+
+#ifdef _LOG
+// CDndNode::Print
+// ***************
+void CDndNode::Print(CDndEngine &aControl)
+	{
+
+	// Just for Unicode, need to "widen" the label!
+	TBuf<63> label;
+	label.Copy(iLabel);
+
+	aControl.ShowTextf(_L("Node: Level = %d, Label = %S"), iLevel, &label);
+ 
+	iRecordList.Print(aControl);
+	iChildren.Print(aControl);
+	}
+#endif
+
+// TDndNodeList.:TDndNodeList
+// **************************
+TDndNodeList::TDndNodeList() : TDblQue<CDndNode>(CDndNode::iOffset) 
+	{}
+
+
+// TDndNodeList::Find
+// ******************
+CDndNode * TDndNodeList::Find(const TNodeLabel &aLabel)
+	{
+	CDndNode *node;
+	TDblQueIter<CDndNode> iter(*this);
+	while ((node = iter++) != NULL)
+		if (DnsCompareNames(node->iLabel, aLabel))
+			return node;
+
+	return NULL;
+	}
+
+
+// TDndNodeList::AddNode
+// *********************
+void TDndNodeList::AddNode(CDndNode &aNode)
+	{
+	AddFirst(aNode);
+	}
+
+// TDndNodeList::DeleteNode
+// ************************
+void TDndNodeList::DeleteNode(CDndNode *const aNode)
+	{
+	aNode->iDlink.Deque();
+	delete aNode;
+	}
+
+#ifdef _LOG
+// TDndNodeList::Print
+// *******************
+void TDndNodeList::Print(CDndEngine &aControl)
+	{
+	aControl.ShowText(_L("Node list: "));
+	if (IsEmpty())
+		aControl.ShowText(_L(" - No nodes"));
+	else
+		{
+		CDndNode *node;
+		TDblQueIter<CDndNode> iter(*this);
+		while((node = iter++) != NULL)
+			node->Print(aControl);
+		}
+	}
+#endif