|
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 // engine.cpp - name resolver core engine |
|
15 // |
|
16 |
|
17 #include "dnd.hrh" |
|
18 #include "engine.h" |
|
19 #include "listener.h" |
|
20 #include "dnd_ini.h" |
|
21 #include "inet6log.h" |
|
22 #include <es_ini.h> |
|
23 #include <timeout.h> |
|
24 #include "in6_version.h" |
|
25 |
|
26 // |
|
27 |
|
28 MDemonEngine *MDemonEngine::NewL(MDemonMain &aMain) |
|
29 /** |
|
30 * Create the instance of CDndEngine. |
|
31 * There can only be one of these. |
|
32 * @param aMain The DLL/EXE "main" interface |
|
33 * @return The Engine interface |
|
34 */ |
|
35 { |
|
36 return new (ELeave) CDndEngine(aMain); |
|
37 } |
|
38 |
|
39 // |
|
40 CDndEngine::~CDndEngine() |
|
41 { |
|
42 // |
|
43 // Ordering is important... Do not close iSS before |
|
44 // all sockets associated with it have been closed! |
|
45 // |
|
46 iHostsFile.Close(); |
|
47 |
|
48 delete iListener; |
|
49 delete iConfig; |
|
50 delete iTimer; |
|
51 |
|
52 iSocket.Close(); |
|
53 iFS.Close(); |
|
54 iSS.Close(); |
|
55 } |
|
56 |
|
57 |
|
58 TInt CDndEngine::GetIniValue(const TDesC &aSection, const TDesC &aName, TInt aDefault, TInt aMin, TInt aMax) |
|
59 /** |
|
60 * Read an integer value from the INI file. |
|
61 * |
|
62 * The INI is a text file (currently named by #DND_INI_DATA). |
|
63 * The used sections are [resolver] and [llmnr] |
|
64 * |
|
65 * @param aSection The INI section name |
|
66 * @param aName The INI variable name |
|
67 * @param aDefault The value returned if variable name not found or is out of range |
|
68 * @param aMin The min of the accepted range |
|
69 * @param aMax The max of the accepted range |
|
70 */ |
|
71 { |
|
72 LOG(_LIT(KFormat, "\t[%S] %S = %d")); |
|
73 LOG(_LIT(KFormatInv, "\t[%S] %S = %d is invalid")); |
|
74 |
|
75 TInt value; |
|
76 if (!FindVar(aSection, aName, value)) |
|
77 value = aDefault; |
|
78 else if (value < aMin || value > aMax) |
|
79 { |
|
80 LOG(Log::Printf(KFormatInv, &aSection, &aName, value)); |
|
81 value = aDefault; |
|
82 } |
|
83 LOG(Log::Printf(KFormat, &aSection, &aName, value)); |
|
84 return value; |
|
85 } |
|
86 |
|
87 void CDndEngine::GetIniAddress(const TDesC &aSection, const TDesC &aName, const TDesC &aDefault, TIp6Addr &aAddr) |
|
88 /** |
|
89 * Read an address value from the INI file. |
|
90 * |
|
91 * The INI is a text file (currently named by #DND_INI_DATA). |
|
92 * The currently used sections are [resolver] and [llmnr]. |
|
93 * |
|
94 * The default is used if INI file does not specify address or the specified |
|
95 * address is not syntactically correct. If the default is also bad, the |
|
96 * aAddr will be unspecified. |
|
97 * |
|
98 * @param aSection The INI section name |
|
99 * @param aName The INI variable name |
|
100 * @param aDefault The default value for the variable (string format) |
|
101 * @retval aAddr The address |
|
102 */ |
|
103 { |
|
104 TInetAddr addr; |
|
105 TPtrC str; |
|
106 |
|
107 if (!FindVar(aSection, aName, str)) |
|
108 str.Set(aDefault); |
|
109 const TInt value = addr.Input(str); |
|
110 // If the parameter is bad, then use the aDefault, but show the |
|
111 // parameter value and result. (If aDefault is bad, Input is done |
|
112 // twice to it, both fail and address will be unspecified.) |
|
113 if (value != KErrNone) |
|
114 (void)addr.Input(aDefault); |
|
115 |
|
116 if (addr.Family() != KAfInet6) |
|
117 addr.ConvertToV4Mapped(); |
|
118 aAddr = addr.Ip6Address(); |
|
119 LOG(_LIT(KFormatAddr, "\t[%S] %S = %S [err=%d]")); |
|
120 LOG(Log::Printf(KFormatAddr, &aSection, &aName, &str, value)); |
|
121 } |
|
122 |
|
123 void CDndEngine::ConstructL() |
|
124 /** |
|
125 * Construct the engine. |
|
126 * |
|
127 * Open file and socket server sessions, read configuration parameters |
|
128 * from [resolver] and [lmnr] sections, create the timeout |
|
129 * manager (MTimeoutManager) and listener (CDndListener) instances. |
|
130 */ |
|
131 { |
|
132 LOG(Log::Printf(_L("--- DND starting, version: [%S] ---"), &KInet6Version)); |
|
133 // |
|
134 // Start Socket Reader activity |
|
135 // |
|
136 CheckResultL(_L("Active Scheduler"), CActiveScheduler::Current() == NULL); |
|
137 CheckResultL(_L("Connect to File server"), iFS.Connect()); |
|
138 CheckResultL(_L("Connect to Socket server"), iSS.Connect()); |
|
139 CheckResultL(_L("Opening socket for Get/SetOpt"), iSocket.Open(iSS, KAfInet, KSockDatagram, KProtocolInetUdp)); |
|
140 // The utility socket should be pretty much "invisible", so disable some things... |
|
141 (void)iSocket.SetOpt(KSoUserSocket, KSolInetIp, 0); |
|
142 (void)iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0); |
|
143 // Failing to open hosts file is not a fatal error. |
|
144 (void)CheckResult(_L("Opening hosts file"), iHostsFile.Open()); |
|
145 |
|
146 // |
|
147 // Setup Configuration Parameters |
|
148 // |
|
149 iParams.iRetries = GetIniValue(DND_INI_RESOLVER, DND_INI_RETRIES, KDndIni_Retries, 1, 255); |
|
150 iParams.iMinTime = GetIniValue(DND_INI_RESOLVER, DND_INI_MINTIME, KDndIni_MinTime, 1, KMaxTInt); |
|
151 iParams.iMaxTime = GetIniValue(DND_INI_RESOLVER, DND_INI_MAXTIME, KDndIni_MaxTime, 1, KMaxTInt); |
|
152 iParams.iSetupTime = GetIniValue(DND_INI_RESOLVER, DND_INI_SETUPTIME, KDndIni_SetupTime, 1, KMaxTInt); |
|
153 iParams.iSetupPoll = GetIniValue(DND_INI_RESOLVER, DND_INI_SETUPPOLL, KDndIni_SetupPoll, 1, KMaxTInt); |
|
154 iParams.iSprayMode = GetIniValue(DND_INI_RESOLVER, DND_INI_SPRAYMODE); |
|
155 iParams.iSkipNotFound = GetIniValue(DND_INI_RESOLVER, DND_INI_SKIPNOTFOUND); |
|
156 iParams.iQueryHack = GetIniValue(DND_INI_RESOLVER, DND_INI_QUERYHACK); |
|
157 iParams.iFlushOnConfig = GetIniValue(DND_INI_RESOLVER, DND_INI_FLUSHONCONFIG); |
|
158 iParams.iQueryOrder = GetIniValue(DND_INI_RESOLVER, DND_INI_QUERYORDER, KDndIni_QueryOrder, 0, 5); |
|
159 #ifdef _LOG |
|
160 { |
|
161 if (iParams.iQueryOrder & KQueryOrder_OneQuery) |
|
162 { |
|
163 _LIT(a, "A"); |
|
164 _LIT(aaaa, "AAAA"); |
|
165 Log::Printf(_L("\t\t= (only %S)"), |
|
166 (iParams.iQueryOrder & KQueryOrder_PreferA) ? &a : &aaaa); |
|
167 } |
|
168 else |
|
169 { |
|
170 _LIT(sequentially, "sequentially"); |
|
171 _LIT(parallel, "in parallel"); |
|
172 _LIT(aaaa_a, "AAAA, A"); |
|
173 _LIT(a_aaaa, "A, AAAA"); |
|
174 Log::Printf(_L("\t\t= (%S %S)"), |
|
175 (iParams.iQueryOrder & KQueryOrder_PreferA) ? &a_aaaa : &aaaa_a, |
|
176 (iParams.iQueryOrder & KQueryOrder_Parallel) ? ¶llel : &sequentially); |
|
177 } |
|
178 } |
|
179 #endif |
|
180 iParams.iEDNS0 = GetIniValue(DND_INI_RESOLVER, DND_INI_EDNS0, KDndIni_EDNS0, KDnsMinHeader, 65000); |
|
181 |
|
182 #ifdef LLMNR_ENABLED |
|
183 iParams.iLlmnrLlOnly = GetIniValue(DND_INI_LLMNR, LLMNR_INI_LLONLY, KLlmnrIni_LlOnly); |
|
184 iParams.iLlmnrPort = GetIniValue(DND_INI_LLMNR, LLMNR_INI_PORT, KLlmnrIni_Port, 0, 65535); |
|
185 iParams.iLlmnrRetries = GetIniValue(DND_INI_LLMNR, LLMNR_INI_RETRIES, KLlmnrIni_Retries, 1, 255); |
|
186 iParams.iLlmnrMinTime = GetIniValue(DND_INI_LLMNR, LLMNR_INI_MINTIME, KLlmnrIni_MinTime, 0, KMaxTInt); |
|
187 iParams.iLlmnrMaxTime = GetIniValue(DND_INI_LLMNR, LLMNR_INI_MAXTIME, KLlmnrIni_MaxTime, 1, KMaxTInt); |
|
188 iParams.iLlmnrHoplimit = GetIniValue(DND_INI_LLMNR, LLMNR_INI_HOPLIMIT, KLlmnrIni_Hoplimit, -1, 255); |
|
189 |
|
190 // Note: both addresses are stored as IPv6 (TIp6Addr) |
|
191 GetIniAddress(DND_INI_LLMNR, LLMNR_INI_IPV4ADDR, KLlmnrIni_Ipv4Addr, iParams.iLlmnrIpv4); |
|
192 GetIniAddress(DND_INI_LLMNR, LLMNR_INI_IPV6ADDR, KLlmnrIni_Ipv6Addr, iParams.iLlmnrIpv6); |
|
193 #endif |
|
194 |
|
195 // Setup the timeout manager |
|
196 iTimer = TimeoutFactory::NewL(); |
|
197 // Setup the "real" DNS resolver main |
|
198 iListener = MDndListener::NewL(*this); |
|
199 UnloadConfigurationFile(); |
|
200 } |
|
201 |
|
202 void CDndEngine::HandleCommandL(TInt aCommand) |
|
203 { |
|
204 switch(aCommand) |
|
205 { |
|
206 case EDndDump: |
|
207 if (iListener) |
|
208 iListener->HandleCommandL(aCommand); |
|
209 else |
|
210 iMain.Write(_L("Listener not active.\n")); |
|
211 break; |
|
212 |
|
213 default: |
|
214 // No own commands, pass the buck to other modules |
|
215 if (iListener) |
|
216 iListener->HandleCommandL(aCommand); |
|
217 } |
|
218 } |
|
219 |
|
220 // CDndEngine::CheckResult |
|
221 // *********************** |
|
222 TInt CDndEngine::CheckResult(const TDesC &aText, TInt aResult) |
|
223 /** |
|
224 * If the result parameter is not KErrNone, output the |
|
225 * error message (with error number). |
|
226 * |
|
227 * @param aText message to be output in case of error |
|
228 * @param aResult to be tested |
|
229 * @return aResult |
|
230 */ |
|
231 { |
|
232 _LIT(KFormat, "%S Error=%d"); |
|
233 |
|
234 if (aResult != KErrNone) |
|
235 ShowTextf(KFormat, &aText, aResult); |
|
236 return aResult; |
|
237 } |
|
238 |
|
239 // CDndEngine::CheckResultL |
|
240 // ************************ |
|
241 void CDndEngine::CheckResultL(const TDesC &aText, TInt aResult) |
|
242 /** |
|
243 * Output success or fail message, and Leave if the code is not |
|
244 * KErrNone. |
|
245 * |
|
246 * @param aText message to be output in case of error |
|
247 * @param aResult to be tested |
|
248 */ |
|
249 { |
|
250 if (CheckResult(aText, aResult) != KErrNone) |
|
251 User::Leave(aResult); |
|
252 } |
|
253 |
|
254 // CDndEngine::ShowText |
|
255 // ******************** |
|
256 void CDndEngine::ShowText(const TDesC &aText) |
|
257 /** |
|
258 * Write a text message. |
|
259 * |
|
260 * @param aText is the message |
|
261 */ |
|
262 { |
|
263 iMain.Write(aText); |
|
264 } |
|
265 |
|
266 // CDndEngine::ShowTextf |
|
267 // ********************* |
|
268 void CDndEngine::ShowTextf(TRefByValue<const TDesC> aFmt, ...) |
|
269 /** |
|
270 * Write a message using format string. |
|
271 * |
|
272 * @param aFmt is the format string |
|
273 */ |
|
274 { |
|
275 //coverity[var_decl]; |
|
276 VA_LIST list; |
|
277 VA_START(list,aFmt); |
|
278 //coverity[uninit_use_in_call]; |
|
279 iMain.WriteList(aFmt, list); |
|
280 } |
|
281 |
|
282 // CDndEngine::LoadConfigurationFile |
|
283 // ********************************* |
|
284 TBool CDndEngine::LoadConfigurationFile() |
|
285 /** |
|
286 * Load the configuration file. |
|
287 * Load the DND configuration file (INI file) into memory (iConfig), |
|
288 * if not already loaded. Only try loading once, if attempt |
|
289 * fails. |
|
290 * The CDndEngine::FindVar functions call this implicitly. There is |
|
291 * no need to call this explicitly. |
|
292 * |
|
293 * @return |
|
294 * @li TRUE, if configuration availabe (iConfig != NULL) |
|
295 * @li FALSE, if configuration file is not available |
|
296 */ |
|
297 { |
|
298 if (iConfig) |
|
299 return TRUE; // Already loaded! |
|
300 // if iConfigErr != 0 (KErrNone), then an attempt for |
|
301 // loading configuration has been made and failed, |
|
302 // assume it never will succeed and avoid further |
|
303 // attemps on each FindVar... |
|
304 if (iConfigErr) |
|
305 return FALSE; |
|
306 LOG(Log::Printf(_L("CDndEngine::LoadConfigurationFile(): %S"), &DND_INI_DATA)); |
|
307 TRAP(iConfigErr, iConfig = CESockIniData::NewL(DND_INI_DATA)); |
|
308 return (iConfig != NULL); |
|
309 } |
|
310 |
|
311 // CDndEngine::UnloadConfigurationFile |
|
312 // *********************************** |
|
313 void CDndEngine::UnloadConfigurationFile() |
|
314 /** |
|
315 * Free the configuration data. |
|
316 * The configuration information (INI file in iConfig) can be unloaded, if it is |
|
317 * assumed that no further need for configuration is required. |
|
318 */ |
|
319 { |
|
320 delete iConfig; |
|
321 iConfig = NULL; |
|
322 iConfigErr = 0; |
|
323 } |
|
324 |
|
325 // |
|
326 // Access to the configuration file |
|
327 TBool CDndEngine::FindVar(const TDesC &aSection, const TDesC &aVarName, TPtrC &aResult) |
|
328 /** |
|
329 * @param aSection the section name in the configution |
|
330 * @param aVarName the variable name within section |
|
331 * @retval aResult variable value, if found |
|
332 * @return |
|
333 * @li TRUE, if variable found |
|
334 * @li FALSE, if not found |
|
335 */ |
|
336 { |
|
337 if (LoadConfigurationFile()) |
|
338 { |
|
339 ASSERT(iConfig); // <-- lint gag |
|
340 return iConfig->FindVar(aSection, aVarName, aResult); |
|
341 } |
|
342 return FALSE; |
|
343 } |
|
344 |
|
345 TBool CDndEngine::FindVar(const TDesC &aSection, const TDesC &aVarName, TInt &aResult) |
|
346 /** |
|
347 * @param aSection the section name in the configution |
|
348 * @param aVarName the variable name within section |
|
349 * @retval aResult variable value, if found |
|
350 * @return |
|
351 * @li TRUE, if variable found |
|
352 * @li FALSE, if not found |
|
353 */ |
|
354 { |
|
355 if (LoadConfigurationFile()) |
|
356 { |
|
357 ASSERT(iConfig); // <-- lint gag |
|
358 return iConfig->FindVar(aSection, aVarName, aResult); |
|
359 } |
|
360 return FALSE; |
|
361 } |