|
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 // node.cpp - structures to hold node information |
|
15 // CDndNode object acts as a node in the tree that represents the cache for the DNS responses. |
|
16 // TDndNodeList is a linked list of CDndNode objects. |
|
17 // |
|
18 |
|
19 #include "node.h" |
|
20 #include "engine.h" |
|
21 #include <networking/dnd_err.h> |
|
22 #include "inet6log.h" |
|
23 |
|
24 const TInt CDndNode::iOffset = _FOFF(CDndNode, iDlink); |
|
25 |
|
26 // CDndNode::CDndNode |
|
27 // ****************** |
|
28 CDndNode::CDndNode(CDndNode *const aParent, const TInt aLevel, const TNodeLabel &aLabel) |
|
29 : iParent(aParent), iLevel(aLevel), iLabel(aLabel) |
|
30 { |
|
31 } |
|
32 |
|
33 // CDndNode::~CDndNode |
|
34 // ******************* |
|
35 CDndNode::~CDndNode() |
|
36 { |
|
37 // |
|
38 // Node can NEVER be deleted, if it has children or records! |
|
39 // |
|
40 __ASSERT_ALWAYS(IsEmpty(), User::Panic(_L("DND"), 0)); |
|
41 } |
|
42 |
|
43 // CDndNode::Cleanup |
|
44 // ***************** |
|
45 /** |
|
46 // Starting from current node, delete nodes in the path |
|
47 // if they have no records and no children. |
|
48 // |
|
49 // Maintain the "cache invariant": whenever control is outside |
|
50 // the cache implementation, the cache must not contain any |
|
51 // nodes that have no child nodes and no records (with exception |
|
52 // of the root nodes at level 0, iParent == NULL) |
|
53 */ |
|
54 void CDndNode::Cleanup() |
|
55 { |
|
56 CDndNode *current = this; |
|
57 while (current->iParent && current->IsEmpty()) |
|
58 { |
|
59 CDndNode *parent = current->iParent; |
|
60 parent->DeleteNode(current); |
|
61 current = parent; |
|
62 } |
|
63 } |
|
64 |
|
65 // CDndNode::DeleteNode |
|
66 // ******************** |
|
67 void CDndNode::DeleteNode(CDndNode *const aNode) |
|
68 { |
|
69 iChildren.DeleteNode(aNode); |
|
70 } |
|
71 |
|
72 |
|
73 // CDndNode::DeleteRecord |
|
74 // ********************** |
|
75 /** |
|
76 // This method must not be called by anyone else except the |
|
77 // CDndRecord::Delete(). |
|
78 // |
|
79 // The call will detach the record instance from this node, |
|
80 // deletes the record instance, and also activates the |
|
81 // cleanup, which deletes a path of nodes, if they have |
|
82 // no records and no children. |
|
83 // |
|
84 // @param aRecord |
|
85 // specifies the record to be deleted. This record must |
|
86 // exist and be owned by the node |
|
87 */ |
|
88 void CDndNode::DeleteRecord(CDndRecord *const aRecord) |
|
89 { |
|
90 iRecordList.Delete(aRecord); |
|
91 Cleanup(); |
|
92 } |
|
93 |
|
94 |
|
95 |
|
96 // CDndNode::FindL |
|
97 // *************** |
|
98 /** |
|
99 // Split the dotted name into components labels and locate the |
|
100 // node at the end of the path defined by those labels. The |
|
101 // search starts from the current node. If necessary, the path |
|
102 // is created (aFlag != 0). |
|
103 // |
|
104 // After the end node of the path is located (or created), a |
|
105 // matching record is located (or created). |
|
106 // |
|
107 // @param aName defines the domain name |
|
108 // @param aFlag |
|
109 // if value is FALSE, only search is performed and a NULL returned if node |
|
110 // is not found. If value is TRUE, the necessary path and final node is |
|
111 // created, if they don't exist yet. |
|
112 // @param aType the type of the record |
|
113 // @param aClass the class of the record |
|
114 // @param aLRU the LRU list into which the record will belong |
|
115 // (only used if record is created by this call). |
|
116 // @param aReqTime the current time (of the query) |
|
117 // @returns a pointer to the newly created record |
|
118 // @li NULL, if node does not exist (can only happen, if aFlag == 0! |
|
119 // @li non-NULL pointer to the record matching the aName, aClass and aType |
|
120 // @leave KErrNoMemory |
|
121 // The function leaves for non-recoverable error (out of memory). |
|
122 // Can occur only if aFlag != 0. |
|
123 // @leave KErrDndBadQuery |
|
124 // The query name is not valid as DNS domain name. |
|
125 */ |
|
126 CDndRecord *CDndNode::FindL(const TDesC8 &aName, const TBool aFlag, |
|
127 const EDnsQType aType, const EDnsQClass aClass, |
|
128 TDndRecordLRU &aLRU, const TTime &aReqTime) |
|
129 { |
|
130 CDndNode *current = this; |
|
131 TPtrC8 remaining(aName); |
|
132 |
|
133 while (remaining.Length() > 0) |
|
134 { |
|
135 // extract the next name segment |
|
136 TPtrC8 currentLabel; |
|
137 TInt index = remaining.LocateReverse('.'); |
|
138 if (index == KErrNotFound) |
|
139 { |
|
140 currentLabel.Set(remaining); |
|
141 index = 0; // Desired node is reached |
|
142 } |
|
143 else |
|
144 { |
|
145 if (index <= 0) |
|
146 User::Leave(KErrDndBadQuery); // a name starting with "." is not valid |
|
147 currentLabel.Set(remaining.Mid(index + 1)); |
|
148 } |
|
149 |
|
150 if (currentLabel.Length() == 0) |
|
151 User::Leave(KErrDndBadQuery); // bad name, empty labels "foo..bar" not legal! |
|
152 if (currentLabel.Length() > KDnsMaxLabel) // this should be 63! (DNS hard limit) |
|
153 User::Leave(KErrDndBadQuery); |
|
154 |
|
155 CDndNode *node = current->iChildren.Find(currentLabel); |
|
156 |
|
157 if (node == NULL) |
|
158 { |
|
159 if (!aFlag) |
|
160 return NULL; // Do not insert! |
|
161 node = new CDndNode(current, current->iLevel + 1, currentLabel); |
|
162 if (node == NULL) |
|
163 { |
|
164 current->Cleanup(); |
|
165 User::Leave(KErrNoMemory); |
|
166 } |
|
167 current->iChildren.AddNode(*node); |
|
168 } |
|
169 remaining.Set(remaining.Left(index)); |
|
170 current = node; |
|
171 } |
|
172 |
|
173 CDndRecord *record = current->iRecordList.Find(aType, aClass, aReqTime); |
|
174 if (!aFlag || record != NULL) |
|
175 return record; |
|
176 |
|
177 // |
|
178 // The looked record does not exist yet, create it here |
|
179 // |
|
180 record = new CDndRecord(aLRU, *current, aType, aClass); |
|
181 if (record == NULL) |
|
182 { |
|
183 // This may invalidate 'this' pointer, so careful here! |
|
184 current->Cleanup(); |
|
185 User::Leave(KErrNoMemory); |
|
186 } |
|
187 else |
|
188 current->iRecordList.Add(*record); |
|
189 return record; |
|
190 } |
|
191 |
|
192 #ifdef _LOG |
|
193 // CDndNode::Print |
|
194 // *************** |
|
195 void CDndNode::Print(CDndEngine &aControl) |
|
196 { |
|
197 |
|
198 // Just for Unicode, need to "widen" the label! |
|
199 TBuf<63> label; |
|
200 label.Copy(iLabel); |
|
201 |
|
202 aControl.ShowTextf(_L("Node: Level = %d, Label = %S"), iLevel, &label); |
|
203 |
|
204 iRecordList.Print(aControl); |
|
205 iChildren.Print(aControl); |
|
206 } |
|
207 #endif |
|
208 |
|
209 // TDndNodeList.:TDndNodeList |
|
210 // ************************** |
|
211 TDndNodeList::TDndNodeList() : TDblQue<CDndNode>(CDndNode::iOffset) |
|
212 {} |
|
213 |
|
214 |
|
215 // TDndNodeList::Find |
|
216 // ****************** |
|
217 CDndNode * TDndNodeList::Find(const TNodeLabel &aLabel) |
|
218 { |
|
219 CDndNode *node; |
|
220 TDblQueIter<CDndNode> iter(*this); |
|
221 while ((node = iter++) != NULL) |
|
222 if (DnsCompareNames(node->iLabel, aLabel)) |
|
223 return node; |
|
224 |
|
225 return NULL; |
|
226 } |
|
227 |
|
228 |
|
229 // TDndNodeList::AddNode |
|
230 // ********************* |
|
231 void TDndNodeList::AddNode(CDndNode &aNode) |
|
232 { |
|
233 AddFirst(aNode); |
|
234 } |
|
235 |
|
236 // TDndNodeList::DeleteNode |
|
237 // ************************ |
|
238 void TDndNodeList::DeleteNode(CDndNode *const aNode) |
|
239 { |
|
240 aNode->iDlink.Deque(); |
|
241 delete aNode; |
|
242 } |
|
243 |
|
244 #ifdef _LOG |
|
245 // TDndNodeList::Print |
|
246 // ******************* |
|
247 void TDndNodeList::Print(CDndEngine &aControl) |
|
248 { |
|
249 aControl.ShowText(_L("Node list: ")); |
|
250 if (IsEmpty()) |
|
251 aControl.ShowText(_L(" - No nodes")); |
|
252 else |
|
253 { |
|
254 CDndNode *node; |
|
255 TDblQueIter<CDndNode> iter(*this); |
|
256 while((node = iter++) != NULL) |
|
257 node->Print(aControl); |
|
258 } |
|
259 } |
|
260 #endif |