networkingutils/nameresolverutility/src/engine.cpp
changeset 0 9736f095102e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkingutils/nameresolverutility/src/engine.cpp	Tue Jan 26 15:16:33 2010 +0200
@@ -0,0 +1,575 @@
+// 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:
+// engine.cpp - nslookup client engine
+//
+
+#include <e32math.h>
+#include <e32std.h>
+#include <eikenv.h>
+#include <plpsess.h>	//Used for RRemoteLink
+#include <networking/dnd_err.h>
+#include <dns_ext.h>
+#include <dns_qry.h>
+#include "engine.h"
+#include <nslookup.rsg>
+#include "nslookup.h"
+
+CNslookup::CNslookup(): CActive(EPriorityStandard)
+	{
+	CActiveScheduler::Add(this);	//Adds itself to the scheduler only the first time
+	}
+
+//Sets the remote link to off
+void CNslookup::DisableRemoteLink()
+	{
+	RRemoteLink link;
+	TRemoteLinkStatus state;
+
+	TInt err=link.Open();
+	if (err==KErrNone)
+		{
+		if (link.Status(state)!=KErrNone)
+			return;
+		if (state.iStatus!=TRemoteLinkStatus::EDisabled)
+			{
+			iConsole->WriteLine(_L("Disabling Remote link\n"));
+			link.Disable(); 
+			}
+		link.Close();
+		}
+	}
+
+//Sets all default values. Actually it's no more a L function
+void CNslookup::ConstructL(const TPreferences& aPref)
+	{
+
+	// Base class second-phase construction.
+
+	iHostname=aPref.iHostname;
+	}
+
+//return the current preferences
+void CNslookup::GetPreferences(TPreferences &aPref) const
+	{	
+	aPref.iHostname=iHostname;		//Address to Ping
+	}
+
+void CNslookup::DefaultPreferences(TPreferences &aPref)
+	{	
+	aPref.iHostname=_L("127.0.0.1");
+	}
+
+
+const TDesC* CNslookup::GetHostName() const
+	{
+	return &iHostname;
+	}
+
+void CNslookup::SetHostName(const TDes& aHostname)
+	{
+	iHostname = aHostname;
+	}
+
+void CNslookup::SetConsole(CNslookupContainer* aConsole)
+	{
+	iConsole = aConsole;
+	}
+
+CNslookup::~CNslookup()
+	{
+	Cancel();
+	}
+
+//Shows the error and set the application as not running. 
+//Requires a return after calling it!
+
+void CNslookup::Error(const TDesC& string,TInt error)
+	{
+	TBuf<150> aux;
+	TBuf<100> errtxt;
+
+	CEikonEnv::Static()->GetErrorText( errtxt,error);
+	aux.Append(string);	
+	aux.Append(_L(": "));
+	aux.Append(errtxt);
+	aux.AppendFormat(_L(" (%d)\n"), error);
+	iConsole->WriteLine(aux);
+	}
+
+
+void CNslookup::Stop()
+	{
+	iHostResolv.Close();
+	iSockServ.Close();
+	CEikonEnv::Static()->BusyMsgCancel();
+	}
+
+
+void CNslookup::BeginL()
+	{
+	TInt err=0;
+
+	if (IsRunning())	// There's another instance running
+		return;
+
+	//INITIALIZATION
+
+	DisableRemoteLink();
+
+	iConsole->WriteHostL(iHostname);
+		
+	//connecting the Socket Server
+	err = iSockServ.Connect();	//KESockDefaultMessageSlots
+	if (err!=KErrNone)
+		{
+		Error(_L("Socket Server Error (Connect)"),err);
+		return;
+		}
+
+	err = iHostResolv.Open(iSockServ, KAfInet, KProtocolInetUdp);	// Address Resolver 
+	if (err != KErrNone)
+		{
+		Error(_L("Resolver Error (Open)"),err);
+		iSockServ.Close();
+		return;
+		}
+	iConsole->WriteLine(_L("\nResolving...\n"));	
+	CEikonEnv::Static()->BusyMsgL(R_RESOLVING_NAME);
+
+	TUint16 querytype = KDnsRRTypeInvalid;
+
+	// This lengthy code checks what the user selected as query type in UI dialog
+	switch (iQueryType)
+		{
+	case 0:		// Default (GetName)
+		break;
+	
+	case 1:		// Query A
+		querytype = KDnsRRTypeA;
+		break;
+		
+	case 2:		// Query NS
+		querytype = KDnsRRTypeNS;
+		break;
+	
+	case 3:		// Query CNAME
+		querytype = KDnsRRTypeCNAME;
+		break;
+	
+	case 4:		// Query WKS
+		querytype = KDnsRRTypeWKS;
+		break;
+	
+	case 5:		// Query PTR
+		querytype = KDnsRRTypePTR;
+		break;
+	
+	case 6:		// Query HINFO
+		querytype = KDnsRRTypeHINFO;
+		break;
+	
+	case 7:		// Query MX
+		querytype = KDnsRRTypeMX;
+		break;
+	
+	case 8:		// Query TXT
+		querytype = KDnsRRTypeTXT;
+		break;
+	
+	case 9:		// Query AAAA
+		querytype = KDnsRRTypeAAAA;
+		break;
+		
+	case 10:	// Query SRV
+		querytype = KDnsRRTypeSRV;
+		break;
+	
+	case 11:	// Query NAPTR
+		querytype = KDnsRRTypeNAPTR;
+		break;
+	
+	case 12:	// Query Any
+		querytype = KDnsQTypeANY;
+		break;
+
+#ifdef DND_DCM_EXTENSION				
+	case 13:	// Cache Clear
+		querytype = KDnsQTypeCacheClear;
+		break;
+#endif
+
+	default:
+		break;
+		}
+		
+	// If query type was something else than default using GetName(), use the new
+	// Query() interface instead
+	if (querytype != KDnsRRTypeInvalid)
+		{
+#ifdef __RHOSTRESOLV_QUERY_IF
+		TBuf8<KHostNameLimit> name8;
+		name8.Copy(iHostname);
+		TDnsQuery query(name8, querytype);
+		TPckgC<TDnsQuery> querybuf(query);	
+
+		// Hmm... Esock seems to use the current length when allocating a buffer for result
+		// output. It should use MaxLength() instead, and now we have to do this to get
+		// over with it
+		iResult.SetLength(iResult.MaxLength());
+		iHostResolv.Query(querybuf, iResult, iStatus);
+#else
+		TBuf<80> aux;
+		aux.Copy(_L("Query() interface not supported\n"));
+		iConsole->WriteLine(aux);
+		iQueryType = 0;
+		Stop();
+		return;
+#endif
+		}
+	else
+		{
+		if (iAddress.Input(iHostname) == KErrNone)
+			{
+			iHostResolv.GetByAddress(iAddress, iEntry, iStatus);
+			}
+		else
+			{
+			iHostResolv.GetByName(iHostname, iEntry, iStatus);
+			}
+		}
+
+	iCount = 0;
+	SetActive();	//Sets the object as Active.
+	}
+
+static TPtrC ErrorTextL(const TInt aCode)
+	{
+	switch (aCode)
+		{
+		case KErrNotFound:			return _L("Name not found");
+
+//		case KErrDndTimedOut:		return _L("timed out");
+//		case KErrDndNoHost:			return _L("no host");	// [dubious error code -- eliminate? ]
+//		case KErrDndNoMemorySend:	return _L("Out of memory on send");
+//		case KErrDndNotSent:		return _L("Query not sent");
+		case KErrDndCache:			return _L("Cache error");
+
+		case KErrDndFormat:			return _L("Bad DNS reply format");
+		case KErrDndServerFailure:	return _L("DNS server failed");
+		case KErrDndBadName:		return _L("Name does not exist in DNS");
+		case KErrDndNotImplemented:	return _L("Query not implemented by DNS server");
+		case KErrDndRefused:		return _L("DNS Server refused query");
+
+//		case KErrDndNoMemoryProc:	return _L("Insufficient memory - can not process the response");
+		case KErrDndNoRecord:		return _L("No record found of the desired type and class"); 
+		case KErrDndNameTooBig:		return _L("Buffer overflow");
+		case KErrDndUnknown:		return _L("Error in DND");
+		case KErrDndServerUnusable:	return _L("No answer available from current server");
+		default:
+			break;
+
+		}
+	User::Leave(aCode);
+	// NOTREACHED
+	return _L("");  // to make compiler happy
+	}
+
+void CNslookup::RunL()
+	{
+	TInt src_addr = 0;
+
+	TBuf<100> textIPaddress;	//text address to be displayed
+	TBuf<356> aux;
+
+	if (iStatus != KErrNone)
+		{
+		if (iCount == 0)
+			{
+			// An error message is only shown, if the primary query
+			// failes, and not for subsequent Next() operations.
+			TBuf<100> msg(iHostname);
+
+			TRAPD(err,
+				TPtrC errText = ErrorTextL(iStatus.Int());
+				msg.AppendFormat(_L(" - %S\n"), &errText));
+			if (err == KErrNone)
+				iConsole->WriteLine(msg);
+			else
+				Error(msg, iStatus.Int());
+			}
+		Stop();
+		return;
+		}	
+
+	// Check if we are using the query interface instead of GetName()
+	if (iQueryType != KDnsRRTypeInvalid)
+		{
+#ifdef __RHOSTRESOLV_QUERY_IF
+		QueryResponse();
+		
+		// See explanation of this SetLength() hack above
+		iResult.SetLength(iResult.MaxLength());
+		iHostResolv.QueryGetNext(iResult, iStatus);
+		iCount++;
+		SetActive();
+#endif		
+		return;
+		}
+
+	aux.Append(iEntry().iName);   // maybe the main name is not the entered
+	switch (iEntry().iAddr.Family())
+		{
+	case KAfInet:
+	case KAfInet6:
+		aux.Append(_L(" is "));
+		iHostAddr = TInetAddr::Cast(iEntry().iAddr);	//host address
+		iHostAddr.Output(textIPaddress);
+		aux.Append(textIPaddress);
+		src_addr = iShowSource && !iHostAddr.IsUnspecified();
+		break;
+	case KAfDns:
+		{
+		SDnsRR &rr = TInetDnsRR::Cast(iEntry().iAddr).RR();
+		if (rr.iClass == 1 /* IN */)
+			{
+			if (rr.iType == 2 /* NS */)
+				{
+				aux.Append(_L(" NS"));
+				break;
+				}
+			else if (rr.iType == 6 /* SOA */)
+				{
+				aux.AppendFormat(_L(" SOA serial=%u refresh=%u retry=%u expire=%u min=%u"),
+					(TUint)rr.iSOA.iSerial,
+					(TUint)rr.iSOA.iRefresh,
+					(TUint)rr.iSOA.iRetry,
+					(TUint)rr.iSOA.iExpire,
+					(TUint)rr.iSOA.iMinimum);
+				break;
+				}
+			else if (rr.iType == 15 /* MX */)
+				{
+				aux.AppendFormat(_L(" MX preference=%d"), (TInt)rr.iMX.iPreference);
+				break;
+				}
+			else if (rr.iType == 33 /* SRV */)
+				{
+				aux.AppendFormat(_L(" SRV port=%d priority=%d weight=%d"),
+					(TInt)iEntry().iAddr.Port(), (TInt)rr.iSRV.iPriority, (TInt)rr.iSRV.iWeight);
+				break;
+				}
+			else if (rr.iType == 35 /* NAPTR */)
+				{
+				TPtrC replacement = rr.iNAPTR.REPLACEMENT(iEntry().iName);
+				TPtrC services = rr.iNAPTR.SERVICES(iEntry().iName);
+				TPtrC regexp = rr.iNAPTR.REGEXP(iEntry().iName);
+
+				aux.AppendFormat(_L(" NAPTR order=%d, preference=%d repl=%S services=%S regexp=%S"),
+					(TInt)rr.iNAPTR.iOrder,
+					(TInt)rr.iNAPTR.iPreference,
+					&replacement,
+					&services,
+					&regexp);
+
+				break;
+				}
+			}
+		aux.AppendFormat(_L(" class=%d type=%d"), (TInt)rr.iClass, (TInt)rr.iType);
+		}
+		break;
+	default:
+		break;
+		}
+
+	const TUint flags = iEntry().iFlags;
+	if (flags)
+		{
+		aux.Append(_L(" ( "));
+		if (flags & EDnsAlias)
+			aux.Append(_L("Alias "));
+		if (flags & EDnsAuthoritive)
+			aux.Append(_L("Authoritative "));
+		if (flags & EDnsHostsFile)
+			aux.Append(_L("Hostfile "));
+		if (flags & EDnsServer)
+			aux.Append(_L("DNS "));
+		if (flags & EDnsHostName)
+			aux.Append(_L("MyName "));
+		if (flags & EDnsCache)
+			aux.Append(_L("Cached "));
+		aux.Append(')');
+		}
+	aux.Append(_L("\n"));
+	iConsole->WriteLine(aux);
+	iCount++;
+	if (src_addr)
+		{
+		// Show a matching SRC address.
+		RSocket socket;
+		TPckgBuf<TSoInetIfQuery> opt;
+		opt().iDstAddr = iHostAddr;
+		if (socket.Open(iSockServ, KAfInet, KSockDatagram, KProtocolInetUdp) == KErrNone)
+			{
+			_LIT(KIsVIF, " (VIF)");
+			_LIT(KIsIF, "");
+			_LIT(KNoRoute, "(no route)");
+
+			(void)socket.GetOpt(KSoInetIfQueryByDstAddr, KSolInetIfQuery, opt);
+			socket.Close();
+			opt().iSrcAddr.OutputWithScope(textIPaddress);
+			aux.Format(_L("   src= %S @ %S%S\n"), &textIPaddress, &opt().iName,
+				opt().iName.Length() == 0 ? &KNoRoute() : opt().iIsUp ? &KIsIF() : &KIsVIF());
+			iConsole->WriteLine(aux);
+			}
+		else
+			iConsole->WriteLine(_L("cannot find src, UDP socket open failed\n"));
+		}
+	//
+	// Get next address
+	//
+	iHostResolv.Next(iEntry, iStatus);
+	SetActive();
+	}
+
+void CNslookup::DoCancel()
+	{
+	// Called only from Cancel() if there is pending resolve going on... (IsActive())
+	iHostResolv.Cancel();
+	}
+
+
+// Outputs some text about the Query() response to the console
+void CNslookup::QueryResponse()
+	{
+	TBuf<256> aux;
+	TBuf<128> addrbuf;
+
+	if (iResult.Length() < (TInt)sizeof(TDnsQryRespBase))
+		{
+		aux.AppendFormat(_L("Malformed response (length: %d)\n"), iResult.Length());
+		return;
+		}
+
+	TDnsQryRespBase *respbase = (TDnsQryRespBase *)iResult.Ptr(); //lint !e826 // area length checked above
+	aux.Append(iHostname);
+	aux.AppendFormat(_L(": cl: %d  ttl: %d  "),
+			respbase->RRClass(), respbase->RRTtl());
+
+	// ugh... I'll do this the hard way: temporary buffer for converting from 8-bit
+	// DNS result descriptors to 16-bit descriptor and the append to output buffer.
+	// A better solution will follow a bit later...
+	switch(respbase->RRType())
+		{
+	case KDnsRRTypeA:
+		{
+		const TDnsRespA *const respA = (TDnsRespA *) respbase;
+		respA->HostAddress().Output(addrbuf);
+		aux.Append(_L("type: A  "));
+		aux.Append(_L("addr: "));
+		aux.Append(addrbuf);
+		}
+		break;
+		
+	case KDnsRRTypeAAAA:
+		{
+		const TDnsRespAAAA *const respAAAA = (TDnsRespAAAA *) respbase;
+		respAAAA->HostAddress().Output(addrbuf);
+		aux.Append(_L("type: AAAA  "));
+		aux.Append(_L("addr: "));
+		aux.Append(addrbuf);
+		}
+		break;
+
+	case KDnsRRTypePTR:
+		{
+		const TDnsRespPTR *const respPTR = (TDnsRespPTR *) respbase;
+		aux.Append(_L("type: PTR  "));
+		aux.Append(_L("name: "));
+		addrbuf.Copy(respPTR->HostName());
+		aux.Append(addrbuf);
+		}
+		break;
+		
+	case KDnsRRTypeMX:
+		{
+		const TDnsRespMX *const respMX = (TDnsRespMX *) respbase;
+		aux.Append(_L("type: MX  "));
+		aux.AppendFormat(_L("pref: %d  "), respMX->Pref());
+		aux.Append(_L("name: "));
+		addrbuf.Copy(respMX->HostName());
+		aux.Append(addrbuf);
+		}
+		break;
+		
+	case KDnsRRTypeSRV:
+		{
+		const TDnsRespSRV *const respSRV = (TDnsRespSRV *) respbase;
+		aux.Append(_L("type: SRV  "));
+		aux.AppendFormat(_L("prio: %d  wght: %d  port: %d  targ: "),
+				respSRV->Priority(), respSRV->Weight(), respSRV->Port());
+		addrbuf.Copy(respSRV->Target());
+		aux.Append(addrbuf);
+		}
+		break;
+		
+	case KDnsRRTypeNAPTR:
+		{
+		const TDnsRespNAPTR *const respNAPTR = (TDnsRespNAPTR *) respbase;
+		aux.Append(_L("type: NAPTR  "));
+		aux.AppendFormat(_L("ordr: %d  pref: %d  flag: "));
+		addrbuf.Copy(respNAPTR->Flags());
+		aux.Append(addrbuf);
+		aux.Append(_L("  serv: "));
+		addrbuf.Copy(respNAPTR->Service());
+		aux.Append(addrbuf);
+		aux.Append(_L("  regx: "));
+		addrbuf.Copy(respNAPTR->Regexp());
+		aux.Append(addrbuf);
+		aux.Append(_L("  repl: "));
+		addrbuf.Copy(respNAPTR->Replacement());
+		aux.Append(addrbuf);
+		}
+		break;
+		
+#ifdef DND_DCM_EXTENSION	
+	case KDnsQTypeCacheClear:
+		{
+		aux.Append(_L("  OK"));
+		break;
+		}
+#endif
+
+	default:
+		aux.AppendFormat(_L("Unknown response type: %d"), respbase->RRType());
+		break;
+		}
+			
+	aux.Append(_L("\n"));
+	iConsole->WriteLine(aux);			
+	}
+
+// Stops NSLOOKUP
+
+void CNslookup::EndNslookup()
+	{	
+	Cancel();
+	Stop();
+	}
+
+// Just checks if sending packets from a previous ping
+
+TBool CNslookup::IsRunning() const
+	{
+	return IsActive();
+	}