networkingutils/nameresolverutility/src/engine.cpp
branchRCL_3
changeset 10 4ca382093dae
parent 5 6beaa9cf4752
child 11 493058e57c8c
equal deleted inserted replaced
5:6beaa9cf4752 10:4ca382093dae
     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 					&regexp);
       
   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 	}