tcpiputils/dnd/src/engine.cpp
changeset 0 af10295192d8
child 20 7e41d162e158
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dnd/src/engine.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,361 @@
+// 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 - name resolver core engine
+//
+
+#include "dnd.hrh"
+#include "engine.h"
+#include "listener.h"
+#include "dnd_ini.h"
+#include "inet6log.h"
+#include <es_ini.h>
+#include <timeout.h>
+#include "in6_version.h"
+
+//
+
+MDemonEngine *MDemonEngine::NewL(MDemonMain &aMain)
+	/**
+	* Create the instance of CDndEngine.
+	* There can only be one of these.
+	* @param aMain The DLL/EXE "main" interface
+	* @return The Engine interface
+	*/
+	{
+	return new (ELeave) CDndEngine(aMain);
+	}
+
+//
+CDndEngine::~CDndEngine()
+	{
+	//
+	// Ordering is important... Do not close iSS before
+	// all sockets associated with it have been closed!
+	//
+	iHostsFile.Close();
+
+	delete iListener;
+	delete iConfig;
+	delete iTimer;
+
+	iSocket.Close();
+	iFS.Close();
+	iSS.Close();
+	}
+
+
+TInt CDndEngine::GetIniValue(const TDesC &aSection, const TDesC &aName, TInt aDefault, TInt aMin, TInt aMax)
+	/**
+	* Read an integer value from the INI file.
+	*
+	* The INI is a text file (currently named by #DND_INI_DATA).
+	* The used sections are [resolver] and [llmnr]
+	*
+	* @param aSection The INI section name
+	* @param aName The INI variable name
+	* @param aDefault The value returned if variable name not found or is out of range
+	* @param aMin The min of the accepted range
+	* @param aMax The max of the accepted range
+	*/
+	{
+	LOG(_LIT(KFormat, "\t[%S] %S = %d"));
+	LOG(_LIT(KFormatInv, "\t[%S] %S = %d is invalid"));
+
+	TInt value;
+	if (!FindVar(aSection, aName, value))
+		value = aDefault;
+	else if (value < aMin || value > aMax)
+		{
+		LOG(Log::Printf(KFormatInv, &aSection, &aName, value));
+		value = aDefault;
+		}
+	LOG(Log::Printf(KFormat, &aSection, &aName, value));
+	return value;
+	}
+
+void CDndEngine::GetIniAddress(const TDesC &aSection, const TDesC &aName, const TDesC &aDefault, TIp6Addr &aAddr)
+	/**
+	* Read an address value from the INI file.
+	*
+	* The INI is a text file (currently named by #DND_INI_DATA).
+	* The currently used sections are [resolver] and [llmnr].
+	*
+	* The default is used if INI file does not specify address or the specified
+	* address is not syntactically correct. If the default is also bad, the
+	* aAddr will be unspecified.
+	*
+	* @param aSection The INI section name
+	* @param aName The INI variable name
+	* @param aDefault The default value for the variable (string format)
+	* @retval aAddr The address
+	*/
+	{
+	TInetAddr addr;
+	TPtrC str;
+
+	if (!FindVar(aSection, aName, str))
+		str.Set(aDefault);
+	const TInt value = addr.Input(str);
+	// If the parameter is bad, then use the aDefault, but show the
+	// parameter value and result. (If aDefault is bad, Input is done
+	// twice to it, both fail and address will be unspecified.)
+	if (value != KErrNone)
+		(void)addr.Input(aDefault);
+
+	if (addr.Family() != KAfInet6)
+		addr.ConvertToV4Mapped();
+	aAddr = addr.Ip6Address();
+	LOG(_LIT(KFormatAddr, "\t[%S] %S = %S [err=%d]"));
+	LOG(Log::Printf(KFormatAddr, &aSection, &aName, &str, value));
+	}
+
+void CDndEngine::ConstructL()
+	/**
+	* Construct the engine.
+	*
+	* Open file and socket server sessions, read configuration parameters
+	* from [resolver] and [lmnr] sections, create the timeout
+	* manager (MTimeoutManager) and listener (CDndListener) instances.
+	*/
+	{
+	LOG(Log::Printf(_L("--- DND starting, version: [%S] ---"), &KInet6Version));
+	//
+	// Start Socket Reader activity
+	//
+	CheckResultL(_L("Active Scheduler"), CActiveScheduler::Current() == NULL);
+	CheckResultL(_L("Connect to File server"), iFS.Connect());
+	CheckResultL(_L("Connect to Socket server"), iSS.Connect());
+	CheckResultL(_L("Opening socket for Get/SetOpt"), iSocket.Open(iSS,  KAfInet, KSockDatagram, KProtocolInetUdp));
+	// The utility socket should be pretty much "invisible", so disable some things...
+	(void)iSocket.SetOpt(KSoUserSocket, KSolInetIp, 0);
+	(void)iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0);
+	// Failing to open hosts file is not a fatal error.
+	(void)CheckResult(_L("Opening hosts file"), iHostsFile.Open());
+
+	//
+	// Setup Configuration Parameters
+	//
+	iParams.iRetries = GetIniValue(DND_INI_RESOLVER, DND_INI_RETRIES, KDndIni_Retries, 1, 255);
+	iParams.iMinTime = GetIniValue(DND_INI_RESOLVER, DND_INI_MINTIME, KDndIni_MinTime, 1, KMaxTInt);
+	iParams.iMaxTime = GetIniValue(DND_INI_RESOLVER, DND_INI_MAXTIME, KDndIni_MaxTime, 1, KMaxTInt);
+	iParams.iSetupTime = GetIniValue(DND_INI_RESOLVER, DND_INI_SETUPTIME, KDndIni_SetupTime, 1, KMaxTInt);
+	iParams.iSetupPoll = GetIniValue(DND_INI_RESOLVER, DND_INI_SETUPPOLL, KDndIni_SetupPoll, 1, KMaxTInt);
+	iParams.iSprayMode = GetIniValue(DND_INI_RESOLVER, DND_INI_SPRAYMODE);
+	iParams.iSkipNotFound = GetIniValue(DND_INI_RESOLVER, DND_INI_SKIPNOTFOUND);
+	iParams.iQueryHack = GetIniValue(DND_INI_RESOLVER, DND_INI_QUERYHACK);
+	iParams.iFlushOnConfig = GetIniValue(DND_INI_RESOLVER, DND_INI_FLUSHONCONFIG);
+	iParams.iQueryOrder = GetIniValue(DND_INI_RESOLVER, DND_INI_QUERYORDER, KDndIni_QueryOrder, 0, 5);
+#ifdef _LOG
+		{
+		if (iParams.iQueryOrder & KQueryOrder_OneQuery)
+			{
+			_LIT(a, "A");
+			_LIT(aaaa, "AAAA");
+			Log::Printf(_L("\t\t= (only %S)"),
+				(iParams.iQueryOrder & KQueryOrder_PreferA) ? &a : &aaaa);
+			}
+		else
+			{
+			_LIT(sequentially, "sequentially");
+			_LIT(parallel, "in parallel");
+			_LIT(aaaa_a, "AAAA, A");
+			_LIT(a_aaaa, "A, AAAA");
+			Log::Printf(_L("\t\t= (%S %S)"),
+				(iParams.iQueryOrder & KQueryOrder_PreferA) ? &a_aaaa : &aaaa_a,
+				(iParams.iQueryOrder & KQueryOrder_Parallel) ? &parallel : &sequentially);
+			}
+		}
+#endif
+	iParams.iEDNS0 = GetIniValue(DND_INI_RESOLVER, DND_INI_EDNS0, KDndIni_EDNS0, KDnsMinHeader, 65000);
+
+#ifdef LLMNR_ENABLED
+	iParams.iLlmnrLlOnly = GetIniValue(DND_INI_LLMNR, LLMNR_INI_LLONLY, KLlmnrIni_LlOnly);
+	iParams.iLlmnrPort = GetIniValue(DND_INI_LLMNR, LLMNR_INI_PORT, KLlmnrIni_Port, 0, 65535);
+	iParams.iLlmnrRetries = GetIniValue(DND_INI_LLMNR, LLMNR_INI_RETRIES, KLlmnrIni_Retries, 1, 255);
+	iParams.iLlmnrMinTime = GetIniValue(DND_INI_LLMNR, LLMNR_INI_MINTIME, KLlmnrIni_MinTime, 0, KMaxTInt);
+	iParams.iLlmnrMaxTime = GetIniValue(DND_INI_LLMNR, LLMNR_INI_MAXTIME, KLlmnrIni_MaxTime, 1, KMaxTInt);
+	iParams.iLlmnrHoplimit = GetIniValue(DND_INI_LLMNR, LLMNR_INI_HOPLIMIT, KLlmnrIni_Hoplimit, -1, 255);
+
+	// Note: both addresses are stored as IPv6 (TIp6Addr)
+	GetIniAddress(DND_INI_LLMNR, LLMNR_INI_IPV4ADDR, KLlmnrIni_Ipv4Addr, iParams.iLlmnrIpv4);
+	GetIniAddress(DND_INI_LLMNR, LLMNR_INI_IPV6ADDR, KLlmnrIni_Ipv6Addr, iParams.iLlmnrIpv6);
+#endif
+
+	// Setup the timeout manager
+	iTimer = TimeoutFactory::NewL();
+	// Setup the "real" DNS resolver main
+	iListener = MDndListener::NewL(*this);
+	UnloadConfigurationFile();
+	}
+
+void CDndEngine::HandleCommandL(TInt aCommand)
+	{
+	switch(aCommand)
+		{
+		case EDndDump:
+			if (iListener)
+				iListener->HandleCommandL(aCommand);
+			else
+				iMain.Write(_L("Listener not active.\n"));
+			break;
+
+		default:
+			// No own commands, pass the buck to other modules
+			if (iListener)
+				iListener->HandleCommandL(aCommand);
+		}
+	}
+
+// CDndEngine::CheckResult
+// ***********************
+TInt CDndEngine::CheckResult(const TDesC &aText, TInt aResult)
+	/**
+	* If the result parameter is not KErrNone, output the
+	* error message (with error number).
+	*
+	* @param aText	message to be output in case of error
+	* @param aResult to be tested
+	* @return aResult
+	*/
+	{
+	_LIT(KFormat, "%S Error=%d");
+
+	if (aResult != KErrNone)
+		ShowTextf(KFormat, &aText, aResult);
+	return aResult;
+	}
+
+// CDndEngine::CheckResultL
+// ************************
+void CDndEngine::CheckResultL(const TDesC &aText, TInt aResult)
+	/**
+	* Output success or fail message, and Leave if the code is not
+	* KErrNone.
+	*
+	* @param aText	message to be output in case of error
+	* @param aResult to be tested
+	*/
+	{
+	if (CheckResult(aText, aResult) != KErrNone)
+		User::Leave(aResult);
+	}
+
+// CDndEngine::ShowText
+// ********************
+void CDndEngine::ShowText(const TDesC &aText)
+	/**
+	* Write a text message.
+	*
+	* @param aText	is the message
+	*/
+	{
+	iMain.Write(aText);
+	}
+
+// CDndEngine::ShowTextf
+// *********************
+void CDndEngine::ShowTextf(TRefByValue<const TDesC> aFmt, ...)
+	/**
+	* Write a message using format string.
+	*
+	* @param aFmt	is the format string
+	*/
+	{
+	//coverity[var_decl];
+	VA_LIST list;
+	VA_START(list,aFmt);
+	//coverity[uninit_use_in_call];
+	iMain.WriteList(aFmt, list);
+	}
+
+// CDndEngine::LoadConfigurationFile
+// *********************************
+TBool CDndEngine::LoadConfigurationFile()
+	/**
+	* Load the configuration file.
+	* Load the DND configuration file (INI file) into memory (iConfig),
+	* if not already loaded. Only try loading once, if attempt
+	* fails.
+	* The CDndEngine::FindVar functions call this implicitly. There is
+	* no need to call this explicitly.
+	*
+	* @return
+	* @li	TRUE, if configuration availabe (iConfig != NULL)
+	* @li	FALSE, if configuration file is not available
+	*/
+	{
+	if (iConfig)
+		return TRUE;	// Already loaded!
+	// if iConfigErr != 0 (KErrNone), then an attempt for
+	// loading configuration has been made and failed,
+	// assume it never will succeed and avoid further
+	// attemps on each FindVar...
+	if (iConfigErr)
+		return FALSE;
+	LOG(Log::Printf(_L("CDndEngine::LoadConfigurationFile(): %S"), &DND_INI_DATA));
+	TRAP(iConfigErr, iConfig = CESockIniData::NewL(DND_INI_DATA));
+	return (iConfig != NULL);
+	}
+
+// CDndEngine::UnloadConfigurationFile
+// ***********************************
+void CDndEngine::UnloadConfigurationFile()
+	/**
+	* Free the configuration data.
+	* The configuration information (INI file in iConfig) can be unloaded, if it is
+	* assumed that no further need for configuration is required.
+	*/
+	{
+	delete iConfig;
+	iConfig = NULL;
+	iConfigErr = 0;
+	}
+
+//
+// Access to the configuration file
+TBool CDndEngine::FindVar(const TDesC &aSection, const TDesC &aVarName, TPtrC &aResult)
+	/**
+	* @param aSection	the section name in the configution
+	* @param aVarName	the variable name within section
+	* @retval aResult	variable value, if found
+	* @return
+	* @li TRUE, if variable found
+	* @li FALSE, if not found
+	*/
+	{
+	if (LoadConfigurationFile())
+		{
+		ASSERT(iConfig);	// <-- lint gag
+		return iConfig->FindVar(aSection, aVarName, aResult);
+		}
+	return FALSE;
+	}
+
+TBool CDndEngine::FindVar(const TDesC &aSection, const TDesC &aVarName, TInt &aResult)
+	/**
+	* @param aSection	the section name in the configution
+	* @param aVarName	the variable name within section
+	* @retval aResult	variable value, if found
+	* @return
+	* @li TRUE, if variable found
+	* @li FALSE, if not found
+	*/
+	{
+	if (LoadConfigurationFile())
+		{
+		ASSERT(iConfig);	// <-- lint gag
+		return iConfig->FindVar(aSection, aVarName, aResult);
+		}
+	return FALSE;
+	}