diff -r 000000000000 -r af10295192d8 tcpiputils/dnd/src/engine.cpp --- /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 +#include +#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) ? ¶llel : &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 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; + }