|
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 - nslookup client engine |
|
15 // |
|
16 |
|
17 #include <e32math.h> |
|
18 #include <e32std.h> |
|
19 #include <eikenv.h> |
|
20 #include <plpsess.h> //Used for RRemoteLink |
|
21 #include <networking/dnd_err.h> |
|
22 #include <dns_ext.h> |
|
23 #include <dns_qry.h> |
|
24 #include "engine.h" |
|
25 #include <nslookup.rsg> |
|
26 #include "nslookup.h" |
|
27 |
|
28 CNslookup::CNslookup(): CActive(EPriorityStandard) |
|
29 { |
|
30 CActiveScheduler::Add(this); //Adds itself to the scheduler only the first time |
|
31 } |
|
32 |
|
33 //Sets the remote link to off |
|
34 void CNslookup::DisableRemoteLink() |
|
35 { |
|
36 RRemoteLink link; |
|
37 TRemoteLinkStatus state; |
|
38 |
|
39 TInt err=link.Open(); |
|
40 if (err==KErrNone) |
|
41 { |
|
42 if (link.Status(state)!=KErrNone) |
|
43 return; |
|
44 if (state.iStatus!=TRemoteLinkStatus::EDisabled) |
|
45 { |
|
46 iConsole->WriteLine(_L("Disabling Remote link\n")); |
|
47 link.Disable(); |
|
48 } |
|
49 link.Close(); |
|
50 } |
|
51 } |
|
52 |
|
53 //Sets all default values. Actually it's no more a L function |
|
54 void CNslookup::ConstructL(const TPreferences& aPref) |
|
55 { |
|
56 |
|
57 // Base class second-phase construction. |
|
58 |
|
59 iHostname=aPref.iHostname; |
|
60 } |
|
61 |
|
62 //return the current preferences |
|
63 void CNslookup::GetPreferences(TPreferences &aPref) const |
|
64 { |
|
65 aPref.iHostname=iHostname; //Address to Ping |
|
66 } |
|
67 |
|
68 void CNslookup::DefaultPreferences(TPreferences &aPref) |
|
69 { |
|
70 aPref.iHostname=_L("127.0.0.1"); |
|
71 } |
|
72 |
|
73 |
|
74 const TDesC* CNslookup::GetHostName() const |
|
75 { |
|
76 return &iHostname; |
|
77 } |
|
78 |
|
79 void CNslookup::SetHostName(const TDes& aHostname) |
|
80 { |
|
81 iHostname = aHostname; |
|
82 } |
|
83 |
|
84 void CNslookup::SetConsole(CNslookupContainer* aConsole) |
|
85 { |
|
86 iConsole = aConsole; |
|
87 } |
|
88 |
|
89 CNslookup::~CNslookup() |
|
90 { |
|
91 Cancel(); |
|
92 } |
|
93 |
|
94 //Shows the error and set the application as not running. |
|
95 //Requires a return after calling it! |
|
96 |
|
97 void CNslookup::Error(const TDesC& string,TInt error) |
|
98 { |
|
99 TBuf<150> aux; |
|
100 TBuf<100> errtxt; |
|
101 |
|
102 CEikonEnv::Static()->GetErrorText( errtxt,error); |
|
103 aux.Append(string); |
|
104 aux.Append(_L(": ")); |
|
105 aux.Append(errtxt); |
|
106 aux.AppendFormat(_L(" (%d)\n"), error); |
|
107 iConsole->WriteLine(aux); |
|
108 } |
|
109 |
|
110 |
|
111 void CNslookup::Stop() |
|
112 { |
|
113 iHostResolv.Close(); |
|
114 iSockServ.Close(); |
|
115 CEikonEnv::Static()->BusyMsgCancel(); |
|
116 } |
|
117 |
|
118 |
|
119 void CNslookup::BeginL() |
|
120 { |
|
121 TInt err=0; |
|
122 |
|
123 if (IsRunning()) // There's another instance running |
|
124 return; |
|
125 |
|
126 //INITIALIZATION |
|
127 |
|
128 DisableRemoteLink(); |
|
129 |
|
130 iConsole->WriteHostL(iHostname); |
|
131 |
|
132 //connecting the Socket Server |
|
133 err = iSockServ.Connect(); //KESockDefaultMessageSlots |
|
134 if (err!=KErrNone) |
|
135 { |
|
136 Error(_L("Socket Server Error (Connect)"),err); |
|
137 return; |
|
138 } |
|
139 |
|
140 err = iHostResolv.Open(iSockServ, KAfInet, KProtocolInetUdp); // Address Resolver |
|
141 if (err != KErrNone) |
|
142 { |
|
143 Error(_L("Resolver Error (Open)"),err); |
|
144 iSockServ.Close(); |
|
145 return; |
|
146 } |
|
147 iConsole->WriteLine(_L("\nResolving...\n")); |
|
148 CEikonEnv::Static()->BusyMsgL(R_RESOLVING_NAME); |
|
149 |
|
150 TUint16 querytype = KDnsRRTypeInvalid; |
|
151 |
|
152 // This lengthy code checks what the user selected as query type in UI dialog |
|
153 switch (iQueryType) |
|
154 { |
|
155 case 0: // Default (GetName) |
|
156 break; |
|
157 |
|
158 case 1: // Query A |
|
159 querytype = KDnsRRTypeA; |
|
160 break; |
|
161 |
|
162 case 2: // Query NS |
|
163 querytype = KDnsRRTypeNS; |
|
164 break; |
|
165 |
|
166 case 3: // Query CNAME |
|
167 querytype = KDnsRRTypeCNAME; |
|
168 break; |
|
169 |
|
170 case 4: // Query WKS |
|
171 querytype = KDnsRRTypeWKS; |
|
172 break; |
|
173 |
|
174 case 5: // Query PTR |
|
175 querytype = KDnsRRTypePTR; |
|
176 break; |
|
177 |
|
178 case 6: // Query HINFO |
|
179 querytype = KDnsRRTypeHINFO; |
|
180 break; |
|
181 |
|
182 case 7: // Query MX |
|
183 querytype = KDnsRRTypeMX; |
|
184 break; |
|
185 |
|
186 case 8: // Query TXT |
|
187 querytype = KDnsRRTypeTXT; |
|
188 break; |
|
189 |
|
190 case 9: // Query AAAA |
|
191 querytype = KDnsRRTypeAAAA; |
|
192 break; |
|
193 |
|
194 case 10: // Query SRV |
|
195 querytype = KDnsRRTypeSRV; |
|
196 break; |
|
197 |
|
198 case 11: // Query NAPTR |
|
199 querytype = KDnsRRTypeNAPTR; |
|
200 break; |
|
201 |
|
202 case 12: // Query Any |
|
203 querytype = KDnsQTypeANY; |
|
204 break; |
|
205 |
|
206 #ifdef DND_DCM_EXTENSION |
|
207 case 13: // Cache Clear |
|
208 querytype = KDnsQTypeCacheClear; |
|
209 break; |
|
210 #endif |
|
211 |
|
212 default: |
|
213 break; |
|
214 } |
|
215 |
|
216 // If query type was something else than default using GetName(), use the new |
|
217 // Query() interface instead |
|
218 if (querytype != KDnsRRTypeInvalid) |
|
219 { |
|
220 #ifdef __RHOSTRESOLV_QUERY_IF |
|
221 TBuf8<KHostNameLimit> name8; |
|
222 name8.Copy(iHostname); |
|
223 TDnsQuery query(name8, querytype); |
|
224 TPckgC<TDnsQuery> querybuf(query); |
|
225 |
|
226 // Hmm... Esock seems to use the current length when allocating a buffer for result |
|
227 // output. It should use MaxLength() instead, and now we have to do this to get |
|
228 // over with it |
|
229 iResult.SetLength(iResult.MaxLength()); |
|
230 iHostResolv.Query(querybuf, iResult, iStatus); |
|
231 #else |
|
232 TBuf<80> aux; |
|
233 aux.Copy(_L("Query() interface not supported\n")); |
|
234 iConsole->WriteLine(aux); |
|
235 iQueryType = 0; |
|
236 Stop(); |
|
237 return; |
|
238 #endif |
|
239 } |
|
240 else |
|
241 { |
|
242 if (iAddress.Input(iHostname) == KErrNone) |
|
243 { |
|
244 iHostResolv.GetByAddress(iAddress, iEntry, iStatus); |
|
245 } |
|
246 else |
|
247 { |
|
248 iHostResolv.GetByName(iHostname, iEntry, iStatus); |
|
249 } |
|
250 } |
|
251 |
|
252 iCount = 0; |
|
253 SetActive(); //Sets the object as Active. |
|
254 } |
|
255 |
|
256 static TPtrC ErrorTextL(const TInt aCode) |
|
257 { |
|
258 switch (aCode) |
|
259 { |
|
260 case KErrNotFound: return _L("Name not found"); |
|
261 |
|
262 // case KErrDndTimedOut: return _L("timed out"); |
|
263 // case KErrDndNoHost: return _L("no host"); // [dubious error code -- eliminate? ] |
|
264 // case KErrDndNoMemorySend: return _L("Out of memory on send"); |
|
265 // case KErrDndNotSent: return _L("Query not sent"); |
|
266 case KErrDndCache: return _L("Cache error"); |
|
267 |
|
268 case KErrDndFormat: return _L("Bad DNS reply format"); |
|
269 case KErrDndServerFailure: return _L("DNS server failed"); |
|
270 case KErrDndBadName: return _L("Name does not exist in DNS"); |
|
271 case KErrDndNotImplemented: return _L("Query not implemented by DNS server"); |
|
272 case KErrDndRefused: return _L("DNS Server refused query"); |
|
273 |
|
274 // case KErrDndNoMemoryProc: return _L("Insufficient memory - can not process the response"); |
|
275 case KErrDndNoRecord: return _L("No record found of the desired type and class"); |
|
276 case KErrDndNameTooBig: return _L("Buffer overflow"); |
|
277 case KErrDndUnknown: return _L("Error in DND"); |
|
278 case KErrDndServerUnusable: return _L("No answer available from current server"); |
|
279 default: |
|
280 break; |
|
281 |
|
282 } |
|
283 User::Leave(aCode); |
|
284 // NOTREACHED |
|
285 return _L(""); // to make compiler happy |
|
286 } |
|
287 |
|
288 void CNslookup::RunL() |
|
289 { |
|
290 TInt src_addr = 0; |
|
291 |
|
292 TBuf<100> textIPaddress; //text address to be displayed |
|
293 TBuf<356> aux; |
|
294 |
|
295 if (iStatus != KErrNone) |
|
296 { |
|
297 if (iCount == 0) |
|
298 { |
|
299 // An error message is only shown, if the primary query |
|
300 // failes, and not for subsequent Next() operations. |
|
301 TBuf<100> msg(iHostname); |
|
302 |
|
303 TRAPD(err, |
|
304 TPtrC errText = ErrorTextL(iStatus.Int()); |
|
305 msg.AppendFormat(_L(" - %S\n"), &errText)); |
|
306 if (err == KErrNone) |
|
307 iConsole->WriteLine(msg); |
|
308 else |
|
309 Error(msg, iStatus.Int()); |
|
310 } |
|
311 Stop(); |
|
312 return; |
|
313 } |
|
314 |
|
315 // Check if we are using the query interface instead of GetName() |
|
316 if (iQueryType != KDnsRRTypeInvalid) |
|
317 { |
|
318 #ifdef __RHOSTRESOLV_QUERY_IF |
|
319 QueryResponse(); |
|
320 |
|
321 // See explanation of this SetLength() hack above |
|
322 iResult.SetLength(iResult.MaxLength()); |
|
323 iHostResolv.QueryGetNext(iResult, iStatus); |
|
324 iCount++; |
|
325 SetActive(); |
|
326 #endif |
|
327 return; |
|
328 } |
|
329 |
|
330 aux.Append(iEntry().iName); // maybe the main name is not the entered |
|
331 switch (iEntry().iAddr.Family()) |
|
332 { |
|
333 case KAfInet: |
|
334 case KAfInet6: |
|
335 aux.Append(_L(" is ")); |
|
336 iHostAddr = TInetAddr::Cast(iEntry().iAddr); //host address |
|
337 iHostAddr.Output(textIPaddress); |
|
338 aux.Append(textIPaddress); |
|
339 src_addr = iShowSource && !iHostAddr.IsUnspecified(); |
|
340 break; |
|
341 case KAfDns: |
|
342 { |
|
343 SDnsRR &rr = TInetDnsRR::Cast(iEntry().iAddr).RR(); |
|
344 if (rr.iClass == 1 /* IN */) |
|
345 { |
|
346 if (rr.iType == 2 /* NS */) |
|
347 { |
|
348 aux.Append(_L(" NS")); |
|
349 break; |
|
350 } |
|
351 else if (rr.iType == 6 /* SOA */) |
|
352 { |
|
353 aux.AppendFormat(_L(" SOA serial=%u refresh=%u retry=%u expire=%u min=%u"), |
|
354 (TUint)rr.iSOA.iSerial, |
|
355 (TUint)rr.iSOA.iRefresh, |
|
356 (TUint)rr.iSOA.iRetry, |
|
357 (TUint)rr.iSOA.iExpire, |
|
358 (TUint)rr.iSOA.iMinimum); |
|
359 break; |
|
360 } |
|
361 else if (rr.iType == 15 /* MX */) |
|
362 { |
|
363 aux.AppendFormat(_L(" MX preference=%d"), (TInt)rr.iMX.iPreference); |
|
364 break; |
|
365 } |
|
366 else if (rr.iType == 33 /* SRV */) |
|
367 { |
|
368 aux.AppendFormat(_L(" SRV port=%d priority=%d weight=%d"), |
|
369 (TInt)iEntry().iAddr.Port(), (TInt)rr.iSRV.iPriority, (TInt)rr.iSRV.iWeight); |
|
370 break; |
|
371 } |
|
372 else if (rr.iType == 35 /* NAPTR */) |
|
373 { |
|
374 TPtrC replacement = rr.iNAPTR.REPLACEMENT(iEntry().iName); |
|
375 TPtrC services = rr.iNAPTR.SERVICES(iEntry().iName); |
|
376 TPtrC regexp = rr.iNAPTR.REGEXP(iEntry().iName); |
|
377 |
|
378 aux.AppendFormat(_L(" NAPTR order=%d, preference=%d repl=%S services=%S regexp=%S"), |
|
379 (TInt)rr.iNAPTR.iOrder, |
|
380 (TInt)rr.iNAPTR.iPreference, |
|
381 &replacement, |
|
382 &services, |
|
383 ®exp); |
|
384 |
|
385 break; |
|
386 } |
|
387 } |
|
388 aux.AppendFormat(_L(" class=%d type=%d"), (TInt)rr.iClass, (TInt)rr.iType); |
|
389 } |
|
390 break; |
|
391 default: |
|
392 break; |
|
393 } |
|
394 |
|
395 const TUint flags = iEntry().iFlags; |
|
396 if (flags) |
|
397 { |
|
398 aux.Append(_L(" ( ")); |
|
399 if (flags & EDnsAlias) |
|
400 aux.Append(_L("Alias ")); |
|
401 if (flags & EDnsAuthoritive) |
|
402 aux.Append(_L("Authoritative ")); |
|
403 if (flags & EDnsHostsFile) |
|
404 aux.Append(_L("Hostfile ")); |
|
405 if (flags & EDnsServer) |
|
406 aux.Append(_L("DNS ")); |
|
407 if (flags & EDnsHostName) |
|
408 aux.Append(_L("MyName ")); |
|
409 if (flags & EDnsCache) |
|
410 aux.Append(_L("Cached ")); |
|
411 aux.Append(')'); |
|
412 } |
|
413 aux.Append(_L("\n")); |
|
414 iConsole->WriteLine(aux); |
|
415 iCount++; |
|
416 if (src_addr) |
|
417 { |
|
418 // Show a matching SRC address. |
|
419 RSocket socket; |
|
420 TPckgBuf<TSoInetIfQuery> opt; |
|
421 opt().iDstAddr = iHostAddr; |
|
422 if (socket.Open(iSockServ, KAfInet, KSockDatagram, KProtocolInetUdp) == KErrNone) |
|
423 { |
|
424 _LIT(KIsVIF, " (VIF)"); |
|
425 _LIT(KIsIF, ""); |
|
426 _LIT(KNoRoute, "(no route)"); |
|
427 |
|
428 (void)socket.GetOpt(KSoInetIfQueryByDstAddr, KSolInetIfQuery, opt); |
|
429 socket.Close(); |
|
430 opt().iSrcAddr.OutputWithScope(textIPaddress); |
|
431 aux.Format(_L(" src= %S @ %S%S\n"), &textIPaddress, &opt().iName, |
|
432 opt().iName.Length() == 0 ? &KNoRoute() : opt().iIsUp ? &KIsIF() : &KIsVIF()); |
|
433 iConsole->WriteLine(aux); |
|
434 } |
|
435 else |
|
436 iConsole->WriteLine(_L("cannot find src, UDP socket open failed\n")); |
|
437 } |
|
438 // |
|
439 // Get next address |
|
440 // |
|
441 iHostResolv.Next(iEntry, iStatus); |
|
442 SetActive(); |
|
443 } |
|
444 |
|
445 void CNslookup::DoCancel() |
|
446 { |
|
447 // Called only from Cancel() if there is pending resolve going on... (IsActive()) |
|
448 iHostResolv.Cancel(); |
|
449 } |
|
450 |
|
451 |
|
452 // Outputs some text about the Query() response to the console |
|
453 void CNslookup::QueryResponse() |
|
454 { |
|
455 TBuf<256> aux; |
|
456 TBuf<128> addrbuf; |
|
457 |
|
458 if (iResult.Length() < (TInt)sizeof(TDnsQryRespBase)) |
|
459 { |
|
460 aux.AppendFormat(_L("Malformed response (length: %d)\n"), iResult.Length()); |
|
461 return; |
|
462 } |
|
463 |
|
464 TDnsQryRespBase *respbase = (TDnsQryRespBase *)iResult.Ptr(); //lint !e826 // area length checked above |
|
465 aux.Append(iHostname); |
|
466 aux.AppendFormat(_L(": cl: %d ttl: %d "), |
|
467 respbase->RRClass(), respbase->RRTtl()); |
|
468 |
|
469 // ugh... I'll do this the hard way: temporary buffer for converting from 8-bit |
|
470 // DNS result descriptors to 16-bit descriptor and the append to output buffer. |
|
471 // A better solution will follow a bit later... |
|
472 switch(respbase->RRType()) |
|
473 { |
|
474 case KDnsRRTypeA: |
|
475 { |
|
476 const TDnsRespA *const respA = (TDnsRespA *) respbase; |
|
477 respA->HostAddress().Output(addrbuf); |
|
478 aux.Append(_L("type: A ")); |
|
479 aux.Append(_L("addr: ")); |
|
480 aux.Append(addrbuf); |
|
481 } |
|
482 break; |
|
483 |
|
484 case KDnsRRTypeAAAA: |
|
485 { |
|
486 const TDnsRespAAAA *const respAAAA = (TDnsRespAAAA *) respbase; |
|
487 respAAAA->HostAddress().Output(addrbuf); |
|
488 aux.Append(_L("type: AAAA ")); |
|
489 aux.Append(_L("addr: ")); |
|
490 aux.Append(addrbuf); |
|
491 } |
|
492 break; |
|
493 |
|
494 case KDnsRRTypePTR: |
|
495 { |
|
496 const TDnsRespPTR *const respPTR = (TDnsRespPTR *) respbase; |
|
497 aux.Append(_L("type: PTR ")); |
|
498 aux.Append(_L("name: ")); |
|
499 addrbuf.Copy(respPTR->HostName()); |
|
500 aux.Append(addrbuf); |
|
501 } |
|
502 break; |
|
503 |
|
504 case KDnsRRTypeMX: |
|
505 { |
|
506 const TDnsRespMX *const respMX = (TDnsRespMX *) respbase; |
|
507 aux.Append(_L("type: MX ")); |
|
508 aux.AppendFormat(_L("pref: %d "), respMX->Pref()); |
|
509 aux.Append(_L("name: ")); |
|
510 addrbuf.Copy(respMX->HostName()); |
|
511 aux.Append(addrbuf); |
|
512 } |
|
513 break; |
|
514 |
|
515 case KDnsRRTypeSRV: |
|
516 { |
|
517 const TDnsRespSRV *const respSRV = (TDnsRespSRV *) respbase; |
|
518 aux.Append(_L("type: SRV ")); |
|
519 aux.AppendFormat(_L("prio: %d wght: %d port: %d targ: "), |
|
520 respSRV->Priority(), respSRV->Weight(), respSRV->Port()); |
|
521 addrbuf.Copy(respSRV->Target()); |
|
522 aux.Append(addrbuf); |
|
523 } |
|
524 break; |
|
525 |
|
526 case KDnsRRTypeNAPTR: |
|
527 { |
|
528 const TDnsRespNAPTR *const respNAPTR = (TDnsRespNAPTR *) respbase; |
|
529 aux.Append(_L("type: NAPTR ")); |
|
530 aux.AppendFormat(_L("ordr: %d pref: %d flag: ")); |
|
531 addrbuf.Copy(respNAPTR->Flags()); |
|
532 aux.Append(addrbuf); |
|
533 aux.Append(_L(" serv: ")); |
|
534 addrbuf.Copy(respNAPTR->Service()); |
|
535 aux.Append(addrbuf); |
|
536 aux.Append(_L(" regx: ")); |
|
537 addrbuf.Copy(respNAPTR->Regexp()); |
|
538 aux.Append(addrbuf); |
|
539 aux.Append(_L(" repl: ")); |
|
540 addrbuf.Copy(respNAPTR->Replacement()); |
|
541 aux.Append(addrbuf); |
|
542 } |
|
543 break; |
|
544 |
|
545 #ifdef DND_DCM_EXTENSION |
|
546 case KDnsQTypeCacheClear: |
|
547 { |
|
548 aux.Append(_L(" OK")); |
|
549 break; |
|
550 } |
|
551 #endif |
|
552 |
|
553 default: |
|
554 aux.AppendFormat(_L("Unknown response type: %d"), respbase->RRType()); |
|
555 break; |
|
556 } |
|
557 |
|
558 aux.Append(_L("\n")); |
|
559 iConsole->WriteLine(aux); |
|
560 } |
|
561 |
|
562 // Stops NSLOOKUP |
|
563 |
|
564 void CNslookup::EndNslookup() |
|
565 { |
|
566 Cancel(); |
|
567 Stop(); |
|
568 } |
|
569 |
|
570 // Just checks if sending packets from a previous ping |
|
571 |
|
572 TBool CNslookup::IsRunning() const |
|
573 { |
|
574 return IsActive(); |
|
575 } |