diff -r 000000000000 -r af10295192d8 tcpiputils/dnd/src/node.cpp --- /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 +#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::iOffset) + {} + + +// TDndNodeList::Find +// ****************** +CDndNode * TDndNodeList::Find(const TNodeLabel &aLabel) + { + CDndNode *node; + TDblQueIter 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 iter(*this); + while((node = iter++) != NULL) + node->Print(aControl); + } + } +#endif