tcpiputils/dnd/src/resolver.cpp
changeset 0 af10295192d8
child 53 7e41d162e158
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     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 // resolver.cpp - name resolver
       
    15 //
       
    16 
       
    17 #include <in_sock.h>
       
    18 #include <timeout.h>
       
    19 #include "listener.h"
       
    20 #include "resolver.h"
       
    21 #include "engine.h"
       
    22 #include "hosts.h"
       
    23 #include <networking/dnd_err.h>
       
    24 #include "dns_ext.h"
       
    25 #include "inet6log.h"
       
    26 
       
    27 #ifdef DND_DCM_EXTENSION
       
    28 #include "dnd.hrh"		// EDndFlush
       
    29 #endif
       
    30 
       
    31 #ifdef EXCLUDE_SYMBIAN_DNS_PUNYCODE
       
    32 #undef SYMBIAN_DNS_PUNYCODE
       
    33 #endif //EXCLUDE_SYMBIAN_DNS_PUNYCODE
       
    34 
       
    35 struct SQueryStep
       
    36 	{
       
    37 	EDnsQType iQType;			// the query type
       
    38 	};
       
    39 
       
    40 struct SQueryExtension
       
    41 	{
       
    42 	const TDesC *iPrefix;
       
    43 	SQueryStep iQuery;
       
    44 	};
       
    45 
       
    46 // ...for GetByAddr, perform only PTR query (for each server)
       
    47 const SQueryStep KGetByAddress[1] =
       
    48 	{
       
    49 	{ EDnsQType_PTR }
       
    50 	};
       
    51 
       
    52 // ...for GetByName, try first AAAA and then A (for each server)
       
    53 const SQueryStep KGetByName1[2] =
       
    54 	{
       
    55 	{ EDnsQType_AAAA },
       
    56 	{ EDnsQType_A }
       
    57 	};
       
    58 
       
    59 // ...for GetByName, try first A and then AAAA (for each server)
       
    60 const SQueryStep KGetByName2[2] =
       
    61 	{
       
    62 	{ EDnsQType_A },
       
    63 	{ EDnsQType_AAAA }
       
    64 	};
       
    65 
       
    66 // Define the search order of the sources
       
    67 const TDnsServerScope KSourceOrder[] =
       
    68 	{
       
    69 	EDnsServerScope_HOSTFILE,	// 1. Search hosts file first
       
    70 	EDnsServerScope_UC_GLOBAL,	// 2. Search global DNS
       
    71 #ifdef LLMNR_ENABLED
       
    72 	EDnsServerScope_MC_LOCAL,	// 3. Try Link Local Multicast
       
    73 #endif
       
    74 	};
       
    75 
       
    76 const SQueryExtension KQueryExtension[] =
       
    77 	{
       
    78 #if 0
       
    79 	{ &KDnsExtQType_A,		EDnsQType_A },
       
    80 	{ &KDnsExtQType_AAAA,	EDnsQType_AAAA },
       
    81 	{ &KDnsExtQType_MX,		EDnsQType_MX },
       
    82 	{ &KDnsExtQType_NS,		EDnsQType_NS },
       
    83 	{ &KDnsExtQType_SOA,	EDnsQType_SOA },
       
    84 	{ &KDnsExtQType_CNAME,	EDnsQType_CNAME },
       
    85 	{ &KDnsExtQType_PTR,	EDnsQType_PTR },
       
    86 	{ &KDnsExtQType_SRV,	EDnsQType_SRV },
       
    87 	{ &KDnsExtQType_NAPTR,	EDnsQType_NAPTR },
       
    88 	{ &KDnsExtQType_ANY,	EDnsQType_ANY }
       
    89 #else
       
    90 	// Workaround for ARMV5 compiler bug? Above declaration always
       
    91 	// produces 80 bytes of writable global data. The following
       
    92 	// ugly definition does not.
       
    93 	{ (const TDesC *)&KDnsExtQType_A.iTypeLength,		EDnsQType_A },
       
    94 	{ (const TDesC *)&KDnsExtQType_AAAA.iTypeLength,	EDnsQType_AAAA },
       
    95 	{ (const TDesC *)&KDnsExtQType_MX.iTypeLength,		EDnsQType_MX },
       
    96 	{ (const TDesC *)&KDnsExtQType_NS.iTypeLength,		EDnsQType_NS },
       
    97 	{ (const TDesC *)&KDnsExtQType_SOA.iTypeLength,		EDnsQType_SOA },
       
    98 	{ (const TDesC *)&KDnsExtQType_CNAME.iTypeLength,	EDnsQType_CNAME },
       
    99 	{ (const TDesC *)&KDnsExtQType_PTR.iTypeLength,		EDnsQType_PTR },
       
   100 	{ (const TDesC *)&KDnsExtQType_SRV.iTypeLength,		EDnsQType_SRV },
       
   101 	{ (const TDesC *)&KDnsExtQType_NAPTR.iTypeLength,	EDnsQType_NAPTR },
       
   102 	{ (const TDesC *)&KDnsExtQType_ANY.iTypeLength,		EDnsQType_ANY }
       
   103 #endif
       
   104 	};
       
   105 
       
   106 // KMaxQuerySessions
       
   107 // *****************
       
   108 /**
       
   109 // The maximum number of query sessions for single resolver,
       
   110 // for example, supporting A and AAAA query, requires this
       
   111 // to be at least 2.
       
   112 // (if someone ever adds A6 to the list, it needs to be 3).
       
   113 */
       
   114 const TUint KMaxQuerySessions = 2;
       
   115 
       
   116 // KMaxDeprecated
       
   117 // **************
       
   118 /**
       
   119 // The size of the deprecated answers buffer. When processing
       
   120 // the replies for GetByName, the resolver will first return
       
   121 // those A and AAAA answers, for which there is an existing
       
   122 // route and source address in the current system. Other answers
       
   123 // are put into deprecated buffer, and returned after the
       
   124 // "good" answers.
       
   125 */
       
   126 const TUint KMaxDeprecated = 20;
       
   127 
       
   128 class CDndResolver;
       
   129 
       
   130 /**
       
   131 // The resolver state automaton for one DNS query.
       
   132 //
       
   133 // This executes the state automaton for a single DNS query
       
   134 // (for example A, AAAA, MX, etc.). The processing includes
       
   135 // automatic retransmissions (potentially to multiple DNS
       
   136 // servers) and timeout handling 
       
   137 //
       
   138 // The query process is started by Start() and it will
       
   139 // then proceed independently to the conclusion.
       
   140 // When the query has completed or failed,
       
   141 // CDndResolver::GetNextAnswer() is called.
       
   142 //
       
   143 // In some cases an error is considered to be non-recoverable,
       
   144 // and instead of calling GetNextAnswer(), CDndResolver::QueryDone(error)
       
   145 // is called instead. This cancel the main query processing and
       
   146 // return the indicated error directly to the client process
       
   147 // (RHostResolver).
       
   148 //
       
   149 */
       
   150 class TQuerySession: public MDnsResolver
       
   151 	{
       
   152 	friend class TQuerySessionTimeoutLinkage;
       
   153 public:
       
   154 	// Default constructor
       
   155 	TQuerySession();
       
   156 	// Supplement default constructor
       
   157 	void Init(CDndResolver *const aResolver);
       
   158 	// Open a new session to the DNS handler
       
   159 	void Open();
       
   160 	// Close the session with the DNS handler
       
   161 	void Close();
       
   162 	// Start a DNS query on the session
       
   163 	TBool Start(EDnsQType aQType);
       
   164 
       
   165 	MDnsSession *iSession;		//< Session handle with DndDnsclient
       
   166 	TInt iStatus;				//< Session status / next record to retrieve (if >= 0)
       
   167 	EDnsQType iQType;			//< the query type
       
   168 private:
       
   169 	static inline TInt Max(const TInt a, const TInt b) { return a > b ? a : b;}
       
   170 
       
   171 	// A callback method when the timeout expires
       
   172 	void Timeout(const TTime &aNow);
       
   173 	// Request a call to Timeout after specified time (seconds)
       
   174 	void SetTimer(TUint aTimeout);
       
   175 	// A callback method when the request to DNS handler completes
       
   176 	void ReplyCallback(const TInt aErr);
       
   177 
       
   178 	// Cancel pending operations
       
   179 	void Cancel();
       
   180 	// Activate a query in the DNS handler
       
   181 	void SendDnsQuery();
       
   182 
       
   183 	// Internal, handles the common part of timeout and reply callbacks
       
   184 	void Event(TBool aTimeout);
       
   185 	
       
   186 	CDndResolver *iResolver;	//< The back pointer to resolver
       
   187 
       
   188 	TUint8 iQueryRetry;			//< Current retry index (for the current step)
       
   189 	TUint8 iQueryTimeouts;		//< Number of true timeouts (used by some resolver modes)
       
   190 	TUint8 iServerCount;		//< used in "spray mode" to count the servers.
       
   191 	TUint iWaitingQuerySent:1;	//< used in detecting and timing out interface startup.
       
   192 	TUint iWaitingAfterSpray:1;	//< used only in "spray mode"
       
   193 	TUint iSendingQuery:1;		//< set to 1, when DoQueryL is being called (recursion safeguard in SendDnsQuery)
       
   194 	TUint iPendingQuery:1;		//< set to 1, when DoQueryL is required (recursion safeguard in SendDnsQuery)
       
   195 	TUint iQueryTimeoutValue;	//< The current timeout for waiting the reply AFTER packet is sent
       
   196 public:	// Needed for gcc!
       
   197 	RTimeout iTimeout;
       
   198 #ifdef _LOG
       
   199 	TBuf<2> iName;
       
   200 #endif
       
   201 	};
       
   202 
       
   203 // This ungainly manoevure is forced on us because the offset is not evaluated early enough by GCC3.4 to be
       
   204 // passed as a template parameter
       
   205 #if defined(__X86GCC__) || defined(__GCCE__)
       
   206 #define KQuerySessionTimeoutLinkageOffset 28
       
   207 __ASSERT_COMPILE(KQuerySessionTimeoutLinkageOffset == _FOFF(TQuerySession, iTimeout));
       
   208 #else
       
   209 #define KQuerySessionTimeoutLinkageOffset _FOFF(TQuerySession, iTimeout)
       
   210 #endif
       
   211 
       
   212 class TQuerySessionTimeoutLinkage : public TimeoutLinkage<TQuerySession, KQuerySessionTimeoutLinkageOffset>
       
   213 	{
       
   214 public:
       
   215 	static void Timeout(RTimeout &aLink, const TTime &aNow, TAny * /*aPtr*/)
       
   216 		{
       
   217 		Object(aLink)->Timeout(aNow);
       
   218 		}
       
   219 	};
       
   220 
       
   221 /**
       
   222 // A structure to remember an answer to be retrieved later.
       
   223 */
       
   224 class TDeprecatedAnswer
       
   225 	{
       
   226 public:
       
   227 	inline TDeprecatedAnswer() {}
       
   228 	inline TDeprecatedAnswer(TUint8 aStep, TUint8 aIndex) : iStep(aStep), iIndex(aIndex) {}
       
   229 
       
   230 	TUint8 iStep;		//< query step # (selects session)
       
   231 	TUint8 iIndex;		//< answer index within the query reply
       
   232 	};
       
   233 
       
   234 /**
       
   235 The real implementation of the MDndResolver.
       
   236 
       
   237 Function:
       
   238 
       
   239 @li	Accepts the request (see TDnsRequestBase) from the application for name resolving.
       
   240 @li	Tries to resolve the request from host files or DNS sources
       
   241 @li	Once the request is over (response obtained or time out),
       
   242 	it sends back the response (again TDnsRequestBase) and/or error code
       
   243 	to the application which requested it.
       
   244 
       
   245 See also \ref resolvers
       
   246 
       
   247 This class is designed so that it can be reused for serving
       
   248 different clients. It has the following simplified state diagram:
       
   249 
       
   250 @verbatim
       
   251                    _________________________
       
   252                  /      reuse               \
       
   253                 V                            |
       
   254  construct -> Start() ---> WaitQuery() --> Stop() --> destruct
       
   255                                /  \          ^
       
   256                               |    |         |
       
   257                                \  /         /
       
   258                             QueryDone() ___/
       
   259 
       
   260 @endverbatim
       
   261 @li Start()
       
   262 	serving a specific RHostResolver session. This method is called
       
   263 	from CDndListener, after it has received a new query request
       
   264 	from the stack.
       
   265 @li WaitQuery()
       
   266 	the resolver is waiting for next incoming request
       
   267 	from the RHostResolver.
       
   268 @li QueryDone()
       
   269 	queue a result to be returned to the RHostResolver.
       
   270 @li Stop()
       
   271 	serving the current rquest. This may be called either
       
   272 	internally or from CDndListener.
       
   273 */
       
   274 class CDndResolver : public CBase, public MDndResolver, public MDnsResolver
       
   275 	{
       
   276 	friend class TQuerySession;
       
   277 public:
       
   278 	CDndResolver(const TInt aId, CDndEngine &aControl, MDndListener &aListener, 
       
   279 					MDnsSource &aDnsclient);
       
   280 
       
   281 	void Start(const TDnsMessageBuf &aMsg);	// Starts the resolver
       
   282 	const TDesC8 &ReplyMessage();			// Return reference to the reply buffer.
       
   283 	TUint16 Session() const;				// Return session id of the current query.
       
   284 	void Stop();							// Stop the resolver
       
   285 	virtual ~CDndResolver();
       
   286 
       
   287 	static inline TInt Max(const TInt a, const TInt b) { return a > b ? a : b;}
       
   288 
       
   289 	const TTime &RequestTime() const { return iRequestTime; }
       
   290 	// only used for GetHostName
       
   291 	void ReplyCallback(const TInt aResult);
       
   292 
       
   293 private:
       
   294 	// Return a result to the application
       
   295 	void QueryDone(TInt aResult);
       
   296 	// Wait for the next query from the application
       
   297 	void WaitQuery();
       
   298 	// Select next source for the name resolving (HOSTS, DNS, LLMNR)
       
   299 	void NextSource();
       
   300 	// Cancel all activity and resources being used for the current source
       
   301 	void StopSource();
       
   302 	TBool StartSource();
       
   303 	// Return next result from HOSTS file source
       
   304 	void HOSTFILE_Next();
       
   305 
       
   306 #ifdef _LOG
       
   307 	// Print out debugging information
       
   308 	void ShowQuery(const TDnsMessage &aName, TInt aReply);
       
   309 #endif
       
   310 
       
   311 	// Retrieve next answer, possibly starting retrieval of additional information from source
       
   312 	void GetNextAnswer();
       
   313 	// Used to find alternate DNS servers (in some operating modes)
       
   314 	void ProbeServers();
       
   315 private:
       
   316 	const TInt iId;					//< Resolver instance id (for debugging use)
       
   317 	TTime iRequestTime;				//< Time at which the request was received from the application
       
   318 
       
   319 	// The Query buffer for the reply
       
   320 	TDnsMessageBuf iBuffer;
       
   321 	// The current orignal query being processed.
       
   322 	TDnsMessageBuf iCurrentQuery;
       
   323 
       
   324 	const TDnsServerScope *iSourceList;	//< Information sources
       
   325 	TDnsServerScope iSourceNow;		//< The current source
       
   326 	TUint iQueryStepMaxTime;		//< Maximum time allowed for single query step to complete
       
   327 	TUint iQueryStepMinTime;		//< Minimum time for query step (usage depends on mode)
       
   328 	TUint8 iQueryStepRetries;		//< Additional retries after the primary attempt
       
   329 	TInt iSourceCount;				//< Remaining number of sources.
       
   330 	TInt iNext;						//< Non-zero, if executing Next operation
       
   331 
       
   332 	// Specify Current Query state
       
   333 
       
   334 	const SQueryStep *iQueryStep;	//< The Current Query Process (what queries to make)
       
   335 	SQueryStep iSpecificQuery;		//< Used in implementing the Specific Single Queries
       
   336 	TQuerySession iSession[KMaxQuerySessions]; //< Currently active queries or completed results
       
   337 	TDeprecatedAnswer iDeprecate[KMaxDeprecated];	//< Buffer to store the delayed answers
       
   338 	TUint iPhase;
       
   339 	TUint8 iDeprecatedTop;		//< Number of delayed top answers in iDeprecate[]
       
   340 	TUint8 iDeprecatedBottom;	//< Number of delayed bottom answers in iDeprecate[]
       
   341 	TUint8 iQuerySteps;			//< Number of Query Steps in the process
       
   342 	TUint8 iStepCount;			//< Number of Query Steps activated so far
       
   343 	TUint8 iSessionCount;		//< Number of Query Sessions currently active
       
   344 	/*
       
   345 	// The scope level of the current query.
       
   346 	//
       
   347 	// Currently the level for GetByName and Query is always "NETWORK".
       
   348 	// But, if implemented, it could be "LINK LOCAL", based on the
       
   349 	// queried name, for example, if it ends with ".local".
       
   350 	//
       
   351 	// The level of GetByAddress is the scope level of the address being
       
   352 	// queried.
       
   353 	//
       
   354 	// The query scope limits the sources available to the query: the scope
       
   355 	// of the source must be less or equal to the query scope. (For example,
       
   356 	// GetByAddress for a link local address is only asked from link local
       
   357 	// name resolvers).
       
   358 	*/
       
   359 	TUint8 iQueryScope;
       
   360 	TUint iQueryActive:1;		//< set to 1, when a query is being processed
       
   361 	TUint iQueryIsAddr:1;		//< set to 1, when current query is GetByAddr, = 0, otherwise
       
   362 	TUint iQueryIsSpecial:1;	//< set to 1, when current query is special (for exact DNS query type)
       
   363 	TUint iReadyForAnswer:1;	//< set to 1, when an answer can be delivered back to RHostResolver.
       
   364 	TUint iQueryDoneWait:1;		//< Tells what active object is currently waiting: = 0, if WaitQuery, = 1, if QueryDone
       
   365 	TUint iQueryComplete:1;		//< set to 1, when query is completed fully (no Next allowed)
       
   366 	TUint32 iQueryFlags;		//< Flags to the NewQuery (KDnsMofidier_RD, ...)
       
   367 
       
   368 	TQuerySession iProbe;		//< Use for server probing
       
   369 	CDndEngine &iControl;		//< The control context (for sending errors etc.)
       
   370 	MDndListener &iListener;	//< Only for calling KeepRunning()
       
   371 	MDnsSource &iDnsclient;		//< DNS protocol handler
       
   372 	};
       
   373 
       
   374 
       
   375 // CDndResolverBase::New
       
   376 // *********************
       
   377 MDndResolver *MDndResolver::New(const TInt aId, CDndEngine &aControl, MDndListener &aListener, MDnsSource &aDnsClient)
       
   378 	/**
       
   379 	* Create a new instance of CDndResolver.
       
   380 	*
       
   381 	* This static function creates the real object instance of
       
   382 	* the class that has been derived from CDndResolverBase.
       
   383 	*
       
   384 	* This way, the real implementation of the class is hidden
       
   385 	* from any other module (the real class CDndResolver is only
       
   386 	* declared and known within resolver.cpp module).
       
   387 	*
       
   388 	* @param aId identifies the resolver instance (only for debuggind purpose)
       
   389 	* @param aControl provides access to the DND environment
       
   390 	* @param aListener
       
   391 	*	provides access to the socket listener, which manages the
       
   392 	*	pool of CDndResolver instances and delivers the requests
       
   393 	*	to the resolvers.
       
   394 	* @param aDnsClient
       
   395 	*	provides access to the DNS protocol driver, which implements
       
   396 	*	the DNS protocol details, and manages the associated UDP and
       
   397 	*	TCP sockets.
       
   398 	* @return
       
   399 	*	@li	NULL, if object could not be created (out of memory)
       
   400 	*	@li non-NULL, is a pointer to the newly constructed CDndResolver instance
       
   401 	*/
       
   402 	{
       
   403 	return new(ELeave) CDndResolver(aId, aControl, aListener, aDnsClient);
       
   404 	}
       
   405 
       
   406 // Constructor
       
   407 CDndResolver::CDndResolver(const TInt aId, CDndEngine &aControl, MDndListener &aListener, MDnsSource &aDnsclient)
       
   408 	: iId(aId), iControl(aControl), iListener(aListener), 
       
   409 	  iDnsclient(aDnsclient)
       
   410 	{
       
   411 	// Because array elements cannot have other than default constructors,
       
   412 	// need to initialize the iSession[] and iProbe here..
       
   413 	for (TInt i = KMaxQuerySessions; --i >= 0; )
       
   414 		{
       
   415 		iSession[i].Init(this);
       
   416 		LOG(iSession[i].iName.Format(_L("%d"), i));
       
   417 		}
       
   418 	iProbe.Init(this);
       
   419 	LOG(iProbe.iName = _L("*"));
       
   420 	}
       
   421 
       
   422 // Destructor
       
   423 CDndResolver::~CDndResolver()
       
   424 	{
       
   425 	// Need to cancel TQuerySession's (if any active)
       
   426 	for (TInt i = KMaxQuerySessions; --i >= 0; )
       
   427 		iSession[i].Close();
       
   428 	}
       
   429 
       
   430 
       
   431 #ifdef _LOG
       
   432 // CDndResolver::ShowQuery(aName)
       
   433 // ******************************
       
   434 void CDndResolver::ShowQuery(const TDnsMessage &aPacket, TInt aReply)
       
   435 	/**
       
   436 	* Displays the current query or reply (only a debugging tool).
       
   437 	*
       
   438 	* @param	aPacket	Query or Reply data
       
   439 	* @param	aReply	Query vs. reply
       
   440 	*/
       
   441 	{
       
   442 	_LIT(KReply, " Reply ");
       
   443 	_LIT(KQuery, " Query ");
       
   444 
       
   445 	const TDesC &mode = aReply ? KReply : KQuery;
       
   446 
       
   447 	switch (aPacket.iType)
       
   448 		{
       
   449 		case KDnsRequestType_GetByName:
       
   450 		case KDnsRequestType_GetByAddress:
       
   451 			{
       
   452 			const TNameRecord &rec = aPacket.NameRecord();
       
   453 			TBuf<50> tmp;
       
   454 			TInetAddr::Cast(rec.iAddr).OutputWithScope(tmp);
       
   455 			if (aReply)
       
   456 
       
   457 				Log::Printf(_L("\tresolver[%d] SESSION %d Reply [%d], %S, [%S] result=%d"), iId, aPacket.iSession, rec.iFlags, &rec.iName, &tmp, aPacket.iNext);
       
   458 			else
       
   459 				Log::Printf(_L("\tresolver[%d] SESSION %d Query (%d), %S, [%S]"), iId, aPacket.iSession, aPacket.iNext, &rec.iName, &tmp);
       
   460 			}
       
   461 			break;
       
   462 		case KDnsRequestType_TDnsQuery:
       
   463 			{
       
   464 			if (aReply)
       
   465 				{
       
   466 				const TDndReply &reply = aPacket.Reply();
       
   467 				Log::Printf(_L("\tresolver[%d] SESSION %d Special Reply, type=%d result=%d"), iId, aPacket.iSession, (TInt)reply.RRType(), aPacket.iNext);
       
   468 				}
       
   469 			else
       
   470 				{
       
   471 				const TDnsQuery &query = aPacket.Query();
       
   472 				Log::Printf(_L8("\tresolver[%d] SESSION %d Special Query (%d), %S type=%d"), iId, aPacket.iSession, aPacket.iNext, &query.Data(), (TInt)query.Type());
       
   473 				}
       
   474 			}
       
   475 			break;
       
   476 		case KDnsRequestType_SetHostName:
       
   477 			Log::Printf(_L("\tresolver[%d] SESSION %d SetHostName(%S)%S%d"), iId, aPacket.iSession, &aPacket.HostName(), &mode, aPacket.iNext);
       
   478 			break;
       
   479 		case KDnsRequestType_GetHostName:
       
   480 			Log::Printf(_L("\tresolver[%d] SESSION %d GetHostName(%S)%S%d"), iId, aPacket.iSession, &aPacket.HostName(), &mode, aPacket.iNext);
       
   481 			break;
       
   482 		default:
       
   483 			Log::Printf(_L("\tresolver[%d] SESSION %d Bad TDnsMessagePacket%S(%d,%d)"), iId, aPacket.iSession, &mode, aPacket.iType, aPacket.iNext);
       
   484 			break;
       
   485 		}
       
   486 	}
       
   487 #endif
       
   488 
       
   489 // CDndResolver::Stop
       
   490 // ******************
       
   491 void CDndResolver::Stop()
       
   492 	/**
       
   493 	* Stop serving the current request.
       
   494 	*
       
   495 	* Terminate all pending activity (if any) and mark the
       
   496 	* CDndResolver instace available for a new session.
       
   497 	*/
       
   498 	{
       
   499 	iReadyForAnswer = 0;		// ...just to be safe.
       
   500 	StopSource();				// stop all DNS activity related to this client, if any
       
   501 	if (iQueryActive)
       
   502 		{
       
   503 		iQueryActive = 0;
       
   504         iDnsclient.QueryEnd();
       
   505 		}
       
   506 	LOG(Log::Printf(_L("\tresolver[%d] SESSION %d Stopped"), iId, iCurrentQuery().iSession));
       
   507 	iCurrentQuery().iSession = 0;
       
   508 	iQueryDoneWait = 0;
       
   509 	}
       
   510 
       
   511 
       
   512 // CDndResolver::WaitQuery
       
   513 // ***********************
       
   514 void CDndResolver::WaitQuery()
       
   515 	/**
       
   516 	* Put the CDndResolver to wait a next request from the RHostResolver.
       
   517 	*
       
   518 	* The next request could be a Next, or a new GetByName, GetByAddr or
       
   519 	* Query.
       
   520 	*/
       
   521 	{
       
   522 	iReadyForAnswer = 0;
       
   523 	if (iQueryActive)
       
   524 		{
       
   525 		// There could be active sessions
       
   526 		// doing some queries while we wait for
       
   527 		// client to request something (doing
       
   528 		// parallel queries).
       
   529 		// Leave "query active" on, if any found.
       
   530 		// The information is retrieved during this
       
   531 		// time is/will be available only for
       
   532 		// the Next() query.
       
   533 		for (TInt i = 0;; ++i)
       
   534 			{
       
   535 			if (i == iSessionCount)
       
   536 				{
       
   537 				iQueryActive = 0;
       
   538 				iDnsclient.QueryEnd();
       
   539 				break;
       
   540 				}
       
   541 			if (iSession[i].iStatus == KRequestPending)
       
   542 				break;
       
   543 			};
       
   544 	  }
       
   545 	iQueryDoneWait = 0;
       
   546 	}
       
   547 
       
   548 // CDndResolver::QueryDone
       
   549 // ***********************
       
   550 void CDndResolver::QueryDone(TInt aResult)
       
   551 	/**
       
   552 	* A query has completed, return a result to the RHostResolver.
       
   553 	*
       
   554 	* Prepare for the reply into iBuffer for writing to the
       
   555 	* "gateway socket". When the reply sender of the listener
       
   556 	* is ready to start the transfer, it calls ReplyMessage()
       
   557 	* for the buffer to be sent.
       
   558 	*
       
   559 	* @param	aResult
       
   560 	*	the result code of the query. If KErrNone, the buffer
       
   561 	*	will contain one answer (TNameRecord or some
       
   562 	*	TDnsQryRespBase variant).
       
   563 	*
       
   564 	* If the reply is an error (< 0), this stops all resolving
       
   565 	* activity that might be still going on. An error reply is
       
   566 	* always final, continuation with a Next() is not possible.
       
   567 	*/
       
   568 	{
       
   569 	if (!iReadyForAnswer)
       
   570 		return;		// Gateway is not expecting answer now...
       
   571 	iReadyForAnswer = 0;
       
   572 	iQueryDoneWait = 1;
       
   573 	iBuffer().iNext = aResult;
       
   574 	if (aResult < 0)
       
   575 		{
       
   576 		StopSource();
       
   577 		iBuffer.SetLength(iBuffer().HeaderSize());
       
   578 		}
       
   579 	LOG(ShowQuery(iBuffer(), 1));
       
   580 	iListener.PostReply();	
       
   581 	}
       
   582 
       
   583 // CDndResolver::ReplyMessage
       
   584 // **************************
       
   585 const TDesC8 &CDndResolver::ReplyMessage()
       
   586 	/**
       
   587 	* Return the reply message buffer.
       
   588 	*
       
   589 	* Called by listener sender when it is ready to send the
       
   590 	* reply message to the gateway socket. If this resolver
       
   591 	* has a reply to send, this must return the buffer.
       
   592 	* If no reply is to be sent for this resolver, this must
       
   593 	* return an empty buffer reference.
       
   594 	*
       
   595 	* @return The reply buffer (empty = no reply to send).
       
   596 	*/
       
   597 	{
       
   598 	_LIT8(KNoReply, "");
       
   599 	if (iQueryDoneWait)
       
   600 		{
       
   601 		const TInt result = iBuffer().iNext;
       
   602 		// Only set iQueryComplete, *never* clear it, if already set!
       
   603 		if (result != KErrCompletion && result < 0)
       
   604 			{
       
   605 			iQueryComplete = 1;
       
   606 			}
       
   607 		iQueryDoneWait = 0;
       
   608 		return iBuffer;
       
   609 		}
       
   610 	else
       
   611 		return KNoReply;
       
   612 	}
       
   613 
       
   614 // CDndResolver::Session
       
   615 // *********************
       
   616 TUint16 CDndResolver::Session() const
       
   617 	/**
       
   618 	* Return the current session id.
       
   619 	*
       
   620 	* This function is used by the listener to find out the
       
   621 	* session id of the request that is currently being
       
   622 	* processed by this resolver.
       
   623 	*
       
   624 	* If the resolver is idle (no request under process), then
       
   625 	* this must return 0. All valid session ids are non-zero.
       
   626 	*
       
   627 	* @return The session (or 0, if none).
       
   628 	*/
       
   629 	{
       
   630 	return iCurrentQuery().iSession;
       
   631 	}
       
   632 
       
   633 void CDndResolver::GetNextAnswer()
       
   634 	/**
       
   635 	* Collect, sort and return answers to the application.
       
   636 	*
       
   637 	* Collecting answers from DNS. The answers are sorted into
       
   638 	* three classes:
       
   639 	*
       
   640 	* @li (1)
       
   641 	*	usable addresses (current system has a route and source address for them)
       
   642 	* @li (2)
       
   643 	*	addresses, for which no route exists are put into "TOP" category (if application
       
   644 	*	uses one of these, then most likely, a new interface needs to be activated). These
       
   645 	*	are returned after all usable addresses in class (1) have been returned..
       
   646 	* @li (3)
       
   647 	*	other (non-address) answers to the query
       
   648 	*
       
   649 	* If a GetByName request needs two queries (for example A and AAAA),
       
   650 	* the queries may be performed in parallel or one after the other.
       
   651 	* If queries are performed one at time, this method will automaticly
       
   652 	* start the second query, after the answers (if any) from the first query
       
   653 	* have been processed.
       
   654 	*
       
   655 	* If a query produces any answer belonging to the class (1), they are
       
   656 	* returned to the application as soon as they become available.
       
   657 	* If queries are not done in parallel, and application is satisfied
       
   658 	* with the first answer (does not issue Next()), then the second
       
   659 	* query is never sent.
       
   660 	*
       
   661 	* If a query produces no answers that sort into class (1), both queries
       
   662 	* are always executed fully, before any answers are returned (from class
       
   663 	* (2) or (3)) to the application.
       
   664 	*/
       
   665 	{
       
   666 	if (!iReadyForAnswer)
       
   667 		return;		// Gateway not expecting answer now...
       
   668 
       
   669 	iBuffer = iCurrentQuery;			// Initialize reply to orginal query
       
   670 	TInt pending = 0;
       
   671 	TInt notfound = 0;
       
   672 
       
   673 	// Initialize query buffer flags.
       
   674 	iBuffer().NameRecord().iFlags = 0;
       
   675 
       
   676 	if (iPhase == 0)
       
   677 		{
       
   678 		//
       
   679 		// Collect Phase
       
   680 		//
       
   681 		for (TInt i = 0; i < iSessionCount; ++i)
       
   682 			{
       
   683 			TQuerySession &session = iSession[i];
       
   684 
       
   685 			if (session.iStatus < 0)
       
   686 				{
       
   687 				// Either pending or no results available (all processed or some error state)
       
   688 				// Detect pending queries (only possible to happen if doing queries in parallel)
       
   689 				pending |= (session.iStatus == KRequestPending);
       
   690 				notfound |= (session.iStatus == KErrDndBadName);
       
   691 				continue;
       
   692 				}
       
   693 			for (;;)
       
   694 				{
       
   695 				//
       
   696 				// Values iSession[i].iStatus >= 0 [0..n] is used for remembering
       
   697 				// the number of the next answer to retrieve from the record
       
   698 				const TInt ret = session.iSession->DoNext(iBuffer, session.iStatus);
       
   699 				if (ret != KErrNone)
       
   700 					{
       
   701 					// All available answers have been retrieved.
       
   702 					session.iStatus = ret;
       
   703 					break;
       
   704 					}
       
   705 				// NOTE: session.iStatus++!!!
       
   706 				const TDeprecatedAnswer answer((TUint8)(i), (TUint8)(session.iStatus++));
       
   707 
       
   708 				if (iQueryIsSpecial)
       
   709 					{
       
   710 					// All answers are returned as is for special query
       
   711 					// (no sorting or any other processing is done)
       
   712 					QueryDone(KErrNone);
       
   713 					return;
       
   714 					}
       
   715 
       
   716 				const TInetAddr &addr = TInetAddr::Cast(iBuffer().NameRecord().iAddr);
       
   717 				if (addr.IsUnspecified() || (addr.Family() != KAfInet && addr.Family() != KAfInet6))
       
   718 					{
       
   719 					// ...things like CNAME's fall into here. If running out of
       
   720 					// space, then just ignore these (Top entries are more important)
       
   721 					if (iDeprecatedTop < iDeprecatedBottom)
       
   722 						{
       
   723 						iDeprecate[--iDeprecatedBottom] = answer;
       
   724 						}
       
   725 					}
       
   726 				else if (iDnsclient.CheckAddress(addr) != KErrNone)
       
   727 					{
       
   728 					// There is no route for the address, don't return this yet
       
   729 					if (iDeprecatedTop < KMaxDeprecated)
       
   730 						{
       
   731 						iDeprecate[iDeprecatedTop++] = answer;
       
   732 						// If running out of space, overwrite deprecated bottom entries
       
   733 						// as needed...
       
   734 						if (iDeprecatedTop > iDeprecatedBottom)
       
   735 							iDeprecatedBottom = iDeprecatedTop;
       
   736 						}
       
   737 					}
       
   738 				else
       
   739 					{
       
   740 					// This is a usable address as is, return immediately
       
   741 					QueryDone(KErrNone);
       
   742 					return;
       
   743 					}
       
   744 				}
       
   745 			}
       
   746 		//
       
   747 		// RR records from the current query have been processed.
       
   748 		//
       
   749 		if (pending)
       
   750 			{
       
   751 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d Request(s) pending"), iId, iCurrentQuery().iSession));
       
   752 			// At least one query session is still in progress, continue waiting
       
   753 			// Should set some timeout? what?
       
   754 			return;
       
   755 			}
       
   756 		else if (!notfound && iStepCount < iQuerySteps)
       
   757 			{
       
   758 			// ... but there are alternate steps left, try the next step...
       
   759 			//
       
   760 			// If all DNS servers worked right, there should be no reason to probe
       
   761 			// servers with A, if the probe for AAAA fails. However, sadly, there
       
   762 			// broken things out there, which timeout on AAAA, but do reply to A.
       
   763 			// Thus, if probing is active, restart it for new query type.
       
   764 			if (iProbe.iSession)
       
   765 				(void)iProbe.iSession->PickDefaultServer();
       
   766 
       
   767 			TQuerySession &session = iSession[iSessionCount++];
       
   768 			session.Open();
       
   769 			if (session.Start(iQueryStep[iStepCount++].iQType))
       
   770 				return;
       
   771 			}
       
   772 		}
       
   773 	//
       
   774 	// Return TOP deprecated
       
   775 	//
       
   776 	while (iPhase < iDeprecatedTop)
       
   777 		{
       
   778 		const MDnsSession *session = iSession[iDeprecate[iPhase].iStep].iSession;
       
   779 		const TInt ret = session->DoNext(iBuffer, iDeprecate[iPhase].iIndex);
       
   780 		// There is no route for the address, add info for application.
       
   781 		iBuffer().NameRecord().iFlags |= EDnsNoRoute;		
       
   782 		iPhase++;
       
   783 		if (ret == KErrNone)
       
   784 			{
       
   785 			QueryDone(KErrNone);
       
   786 			return;
       
   787 			}
       
   788 		}
       
   789 	//
       
   790 	// Return BOTTOM deprecated
       
   791 	// (only for GetByAddr or for Next() after GetByName)
       
   792 	//
       
   793 	iPhase = KMaxDeprecated;
       
   794 	if (iQueryIsAddr || iNext)
       
   795 		{
       
   796 		while (iDeprecatedBottom < KMaxDeprecated)
       
   797 			{
       
   798 			const MDnsSession *session = iSession[iDeprecate[iDeprecatedBottom].iStep].iSession;
       
   799 			const TInt ret = session->DoNext(iBuffer, iDeprecate[iDeprecatedBottom].iIndex);
       
   800 			iDeprecatedBottom++;
       
   801 			if (ret == KErrNone)
       
   802 				{
       
   803 				QueryDone(KErrNone);
       
   804 				return;
       
   805 				}
       
   806 			}
       
   807 		}
       
   808 	if (iNext)
       
   809 		QueryDone(iQueryIsAddr ? KErrDndAddrNotFound : KErrDndNameNotFound);
       
   810 	else
       
   811 		// No answers returned from current source, try next
       
   812 		NextSource();
       
   813 	}
       
   814 
       
   815 // CDndResolver::ProbeServers
       
   816 // **************************
       
   817 void CDndResolver::ProbeServers()
       
   818 	/**
       
   819 	* Probing servers.
       
   820 	*
       
   821 	* Send a dummy duplicate query to the next alternate
       
   822 	* server. Used in some resolver modes. The result is ignored
       
   823 	* by resolver, but the side effect is that the DNS protocol
       
   824 	* handler will detect a good server, and make it the default
       
   825 	* for the next try.
       
   826 	*/
       
   827 	{
       
   828 	if (iSessionCount == 0)
       
   829 		return;
       
   830 	if (iProbe.iSession == NULL)
       
   831 		{
       
   832 		// Use the first primary session (iSession[0]) as a template
       
   833 		// for the "probing".
       
   834 		if (iSession[0].iSession == NULL)
       
   835 			return;	// ...oops!?
       
   836 		iProbe.iQType = iSession[0].iQType;
       
   837 		iProbe.iSession = iDnsclient.OpenSession(&iProbe);
       
   838 		if (iProbe.iSession == NULL)
       
   839 			return;
       
   840 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d Probing QType=%d (%S) -- Assigned DNS session [%u]"),
       
   841 			iId, (TInt)iCurrentQuery().iSession, (TInt)iProbe.iQType, &iProbe.iName, (TInt)iProbe.iSession->Instance())); 
       
   842 		// Use the current query as a probe starting point
       
   843 		//(void)iProbe.iSession->NewQuery(*iSession[0].iSession);
       
   844 		(void)iProbe.iSession->NewQuery(iCurrentQuery(),iSourceNow,iQueryFlags | KDnsModifier_PQ);
       
   845 		
       
   846 		// initialize server (which is not tried)
       
   847 		(void)iProbe.iSession->PickDefaultServer();
       
   848 		}
       
   849 	// Start query, but only if there really is another server address
       
   850 	if (iProbe.iSession->PickNewServer())
       
   851 		{
       
   852 		// Note: if DoQueryL fails, we do nothing. This is just probing...
       
   853 		TRAP_IGNORE(iProbe.iSession->DoQueryL(iRequestTime, iProbe.iQType));
       
   854 		}
       
   855 	}
       
   856 
       
   857 
       
   858 // CDndResolver::StopSource
       
   859 // ************************
       
   860 void CDndResolver::StopSource()
       
   861 	/**
       
   862 	* Stop all resolving activity from current source.
       
   863 	*
       
   864 	* The answer can be searched from different sources (such as hosts file,
       
   865 	* global DNS or link local name resolution). Answers from different sources are
       
   866 	* never mixed, and the first source that gives an answer is used.
       
   867 	*
       
   868 	* StopSource() cancels all activity (if any) from current source.
       
   869 	*/
       
   870 	{
       
   871 	// Release sessions, if they were created
       
   872 	while (iSessionCount > 0)
       
   873 		iSession[--iSessionCount].Close();
       
   874 	iProbe.Close();
       
   875 	}
       
   876 
       
   877 
       
   878 // CDndResolver::NextSource
       
   879 // ************************
       
   880 void CDndResolver::NextSource()
       
   881 	/**
       
   882 	* Activate search from next source.
       
   883 	*
       
   884 	* The answer can be searched from different sources (such as hosts file,
       
   885 	* global DNS or link local name resolution). Answers from different sources are
       
   886 	* never mixed, and the first source that gives an answer is used.
       
   887 	*
       
   888 	* NextSource activates the next query source or terminates the
       
   889 	* query, if all sources have been tried.
       
   890 	*/
       
   891 	{
       
   892 
       
   893 	while (iSourceCount > 0)
       
   894 		{
       
   895 		StopSource();	// Cleanup from previous source, if any
       
   896 
       
   897 		// Replies from different source are never mixed
       
   898 		// Restart collecting answers too.
       
   899 		iPhase = 0;
       
   900 		iDeprecatedTop = 0;
       
   901 		iDeprecatedBottom = KMaxDeprecated;
       
   902 		iSourceNow = *iSourceList++;
       
   903 		iSourceCount -= 1;
       
   904 
       
   905 		// Is this source valid for the query scope (e.g. if source is global
       
   906 		// DNS, one should not try to query site or link local queries from it!)
       
   907 		// On the other hand, it is legal to make global scope query to link
       
   908 		// local or site scope servers.
       
   909 		const TUint level = (TUint)Abs((TInt)iSourceNow);
       
   910 		if (iQueryScope < level)
       
   911 			continue;	// Query scope is less than servers scope, try another source!
       
   912 
       
   913 		if (StartSource())
       
   914 			return;
       
   915 		}
       
   916 
       
   917 	// The name could not be resolved by any source
       
   918 	QueryDone(iQueryIsAddr ? KErrDndAddrNotFound : KErrDndNameNotFound);
       
   919 	}
       
   920 
       
   921 
       
   922 // CDndResolver::StartSource
       
   923 // *************************
       
   924 TBool CDndResolver::StartSource()
       
   925 	/**
       
   926 	* Initiate a source.
       
   927 	*
       
   928 	* Start/Activate retrieval of query answers from the current source,
       
   929 	* as defined by CDndResolver::iSourceNow. Three classes of
       
   930 	* sources are supported:
       
   931 	*
       
   932 	* @li	HOST file (= 0)
       
   933 	* @li	Unicast DNS server ( < 0)
       
   934 	* @li	Multicast name resolution service ( > 0)
       
   935 	*
       
   936 	* The absolute value of iSourceNow is the scope
       
   937 	* level of the name resolution source (2 = link local, etc..)  
       
   938 	*
       
   939 	* @returns
       
   940 	*	@li	TRUE, if process has been started (or answer already resolved).
       
   941 	*	@li	FALSE, if the source is not available or usable
       
   942 	*/
       
   943 	{
       
   944 	// If you define more complex queries, needing more than current max of
       
   945 	// steps, then bump up the KMaxQuerySessions! Panic on debug, on release
       
   946 	// just ignore the extra steps.
       
   947 	ASSERT(iQuerySteps <= KMaxQuerySessions);
       
   948 	if (iQuerySteps > KMaxQuerySessions)
       
   949 		iQuerySteps = KMaxQuerySessions;
       
   950 
       
   951 	
       
   952 	const TDndConfigParameters &cf = iControl.GetConfig();
       
   953 
       
   954 	TUint query_order = cf.iQueryOrder;
       
   955 
       
   956 	if (iSourceNow == 0)
       
   957 		{
       
   958 		// HOST file or hostname source
       
   959 		if (!iQueryIsSpecial)
       
   960 			{
       
   961 			// Check if the query is for local host name or my own address.
       
   962 			TInt res;
       
   963 			if (iQueryIsAddr)
       
   964 				res = iDnsclient.GetByAddress(iBuffer().iId, TInetAddr::Cast(iBuffer().NameRecord().iAddr), iNext, iBuffer().NameRecord().iName);
       
   965 			else
       
   966 				res = iDnsclient.GetByName(iBuffer().iId, iBuffer().NameRecord().iName, iNext, TInetAddr::Cast(iBuffer().NameRecord().iAddr));
       
   967 			if (res == KErrNone)
       
   968 				{
       
   969 				LOG(Log::Printf(_L("\tresolver[%d] SESSION %d matched local hostname/address"), iId, iCurrentQuery().iSession));
       
   970 				iBuffer().NameRecord().iFlags = EDnsHostName;
       
   971 				QueryDone(KErrNone);
       
   972 				return TRUE;
       
   973 				}
       
   974 			// ..and now the HOSTS file
       
   975 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d SEARCHING hosts file"), iId, iCurrentQuery().iSession));
       
   976 			TRequestStatus tmp;
       
   977 			if (iQueryIsAddr)
       
   978 				iControl.iHostsFile.GetByAddress(iBuffer().NameRecord(), tmp);
       
   979 			else
       
   980 				iControl.iHostsFile.GetByName(iBuffer().NameRecord(), tmp);
       
   981 			if (tmp.Int() == KErrNone)
       
   982 				{
       
   983 				iBuffer().NameRecord().iFlags = EDnsHostsFile;
       
   984 				QueryDone(KErrNone);
       
   985 				return TRUE;
       
   986 				}
       
   987 			}
       
   988 	
       
   989 		if (iBuffer().iId == 0)
       
   990 			{
       
   991 			// If there is no scope is specified, then only hosts file
       
   992 			// is looked.
       
   993 			QueryDone(KErrCompletion);
       
   994 			return TRUE;
       
   995 			}
       
   996 		// No Answer from the host file, move on to the next
       
   997 		return FALSE;
       
   998 		}
       
   999 	else if (iSourceNow < 0)
       
  1000 		{
       
  1001 		//
       
  1002 		// Unicast DNS source
       
  1003 		//
       
  1004 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d SEARCHING unicast DNS"), iId, iCurrentQuery().iSession));
       
  1005 		// Setup parameters for basic query step (steps are done one after another)
       
  1006 		iQueryStepMaxTime = Max(cf.iMinTime, cf.iMaxTime / iQuerySteps);
       
  1007 		iQueryStepMinTime = cf.iMinTime;
       
  1008 		iQueryStepRetries = (TUint8)cf.iRetries;
       
  1009 		}
       
  1010 	else
       
  1011 		{
       
  1012 		//
       
  1013 		// Multicast DNS source
       
  1014 		//
       
  1015 		// Setup parameters for basic query step 
       
  1016 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d SEARCHING multicast DNS"), iId, iCurrentQuery().iSession));
       
  1017 		query_order |= KQueryOrder_Parallel;	// Multicast steps are always done in parallel
       
  1018 #ifdef LLMNR_ENABLED
       
  1019 		// Assumed: "multicast DNS" == LLMNR!
       
  1020 		iQueryStepMaxTime = Max(cf.iLlmnrMinTime, cf.iLlmnrMaxTime);
       
  1021 		iQueryStepMinTime = cf.iLlmnrMinTime;
       
  1022 		iQueryStepRetries = (TUint8)cf.iLlmnrRetries;
       
  1023 #else
       
  1024 		iQueryStepMaxTime = Max(cf.iMinTime, cf.iMaxTime);
       
  1025 		iQueryStepMinTime = cf.iMinTime;
       
  1026 		iQueryStepRetries = (TUint8)cf.iRetries;
       
  1027 #endif
       
  1028 		}
       
  1029 	//
       
  1030 	// Start the query/queries
       
  1031 	//
       
  1032 	TBool started = FALSE;
       
  1033 	iSessionCount = 0;
       
  1034 	iStepCount = 0;
       
  1035 	while (iStepCount < iQuerySteps)
       
  1036 		{
       
  1037 		TQuerySession &session = iSession[iSessionCount++];
       
  1038 		session.Open();
       
  1039 		if (session.iSession == NULL)
       
  1040 			{
       
  1041 			// If the required session cannot be allocated,
       
  1042 			// abort the request totally.
       
  1043 			QueryDone(session.iStatus);
       
  1044 			return TRUE;
       
  1045 			}
       
  1046 		started |= session.Start(iQueryStep[iStepCount++].iQType);
       
  1047 		if (started && (query_order & KQueryOrder_Parallel) == 0)
       
  1048 			break;
       
  1049 		}
       
  1050 	return started;
       
  1051 	}
       
  1052 
       
  1053 // CDndResolver::HOSTFILE_Next
       
  1054 // ***************************
       
  1055 void CDndResolver::HOSTFILE_Next()
       
  1056 	/**
       
  1057 	* Return next answer from HOST file.
       
  1058 	*
       
  1059 	* The HOST file answers are not currently sorted in any way. The
       
  1060 	* answers are returned as is, in whatever order the host file
       
  1061 	* module returns them.
       
  1062 	*
       
  1063 	* Only TNameRecord based queries are asked from the HOST file
       
  1064 	* (e.g. the standart RHostResolver::GetByName and RHostResolver::GetByAddr).
       
  1065 	* No special queries.
       
  1066 	*/
       
  1067 	{
       
  1068 	// Should never get called with special queries, but if that
       
  1069 	// happens, just return KErrEof as a safety measure...
       
  1070 	TRequestStatus tmp(KErrEof);
       
  1071 	if (!iQueryIsSpecial)
       
  1072 		{
       
  1073 		// Temp. kludge: next indicator for hosts file reader is passed in iFlags!
       
  1074 		iBuffer().NameRecord().iFlags = iNext;
       
  1075 		if (iQueryIsAddr)
       
  1076 			iControl.iHostsFile.GetByAddress(iBuffer().NameRecord(), tmp);
       
  1077 		else
       
  1078 			iControl.iHostsFile.GetByName(iBuffer().NameRecord(), tmp);
       
  1079 		// Note: iHostFile returns the result code in TRequestStatus.
       
  1080 		iBuffer().NameRecord().iFlags = EDnsHostsFile;
       
  1081 		}
       
  1082 	QueryDone(tmp.Int());
       
  1083 	}
       
  1084 
       
  1085 // CDndResolver::Start
       
  1086 // *******************
       
  1087 void CDndResolver::Start(const TDnsMessageBuf &aMsg)
       
  1088 	/**
       
  1089 	* Process a new request from listener/RHostResolver.
       
  1090 	*
       
  1091 	* @param aMsg The request message
       
  1092 	*/
       
  1093 	{
       
  1094 	const TDndConfigParameters &cf = iControl.GetConfig();
       
  1095 
       
  1096 	// Sanity checks -- determine the min size of a proper request
       
  1097 	const TInt min_size = aMsg().HeaderSize() +
       
  1098 		TInt(aMsg().iType == KDnsRequestType_TDnsQuery ? sizeof(TDnsQuery) :
       
  1099 			 aMsg().iType == KDnsRequestType_GetByName ? sizeof(TNameRecord) :
       
  1100 			 aMsg().iType == KDnsRequestType_GetByAddress ? sizeof(TNameRecord) :
       
  1101 			 sizeof(THostName));
       
  1102 	if (aMsg.Length() < min_size) // If short query => treat as cancel!
       
  1103 		{
       
  1104 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d Cancelled by client (len=%d)"), iId, iCurrentQuery().iSession,  aMsg.Length()));
       
  1105 		Stop();
       
  1106 		return;
       
  1107 		}
       
  1108 
       
  1109 	// Stack should never start new request before delivering the response.
       
  1110 	// Exception is the Cancel-request which is treated above.
       
  1111 	ASSERT(iQueryDoneWait == 0);
       
  1112 	
       
  1113 	iBuffer = aMsg;
       
  1114 	//
       
  1115 	// A new command/query from the application
       
  1116 	//
       
  1117 	LOG(ShowQuery(iBuffer(), 0));
       
  1118 
       
  1119 	// If query is not active, it will be after this
       
  1120 	if (iQueryActive == 0)
       
  1121 		{
       
  1122 		iQueryActive = 1;
       
  1123 		iDnsclient.QueryBegin();
       
  1124 		}
       
  1125 
       
  1126 	iReadyForAnswer = 1;			// an answer can now be returned...
       
  1127 	iRequestTime.UniversalTime();	// Set the time of request
       
  1128 
       
  1129 	iNext = iBuffer().iNext;
       
  1130 	if (iNext)
       
  1131 		{
       
  1132 		// This is Next() processing, retrieving
       
  1133 		// the additional records.
       
  1134 		if (iQueryComplete)
       
  1135 			{
       
  1136 			// An application/something is stubbornly calling Next() after
       
  1137 			// receiving an error (query complete) or the query was "one shot"
       
  1138 			// that returned "KErrNone", and was complete at that (no Next).
       
  1139 			// This error should terminate the Next() loop in app!
       
  1140 			QueryDone(KErrNotFound);
       
  1141 			return;
       
  1142 			}
       
  1143 		iBuffer = iCurrentQuery;	// Reset to orginal query (Next() cannot change the query)
       
  1144 		if (iSourceNow == 0)
       
  1145 			HOSTFILE_Next();
       
  1146 		else
       
  1147 			GetNextAnswer();
       
  1148 		}
       
  1149 	else
       
  1150 		{
       
  1151 		//
       
  1152 		// Start processing of new query, not Next()
       
  1153 		//
       
  1154 		iQueryComplete = 0;
       
  1155 		iCurrentQuery = iBuffer;		// Remember current original query
       
  1156 		iQueryFlags = KDnsModifier_RD;	// By default, request recursive querying from the server(s).
       
  1157 		StopSource();
       
  1158 		switch (iBuffer().iType)
       
  1159 			{
       
  1160 			case KDnsRequestType_GetByName:
       
  1161 			case KDnsRequestType_GetByAddress:
       
  1162 				{
       
  1163 				TNameRecord &rec = iCurrentQuery().NameRecord();
       
  1164 
       
  1165 				if (iCurrentQuery().iType == KDnsRequestType_GetByAddress)
       
  1166 					{
       
  1167 					iQueryIsAddr = 1;
       
  1168 					// The scope of GetByAddress query is determined from the scope level
       
  1169 					// of the address being queried.
       
  1170 					iQueryScope = (TUint8)TInetAddr::Cast(rec.iAddr).Ip6Address().Scope();
       
  1171 					iQueryIsSpecial = 0;
       
  1172 					iQueryStep = KGetByAddress;
       
  1173 					iQuerySteps = sizeof(KGetByAddress) / sizeof(KGetByAddress[0]);
       
  1174 					}
       
  1175 				else
       
  1176 					{
       
  1177 					iQueryIsAddr = 0;
       
  1178 					// All getbyname queries are global for now. As a future feature
       
  1179 					// It might be considered, that single label or names ending with
       
  1180 					// ".local" would have have local scope -- msa
       
  1181 					iQueryScope = KIp6AddrScopeNetwork;
       
  1182 
       
  1183 #ifdef DND_DCM_EXTENSION
       
  1184 					iQueryIsSpecial = 0;
       
  1185 					TInt i;
       
  1186 					while ((i = rec.iName.Locate('?')) >= 0)
       
  1187 						{
       
  1188 						const TPtrC prefix = rec.iName.Left(i+1);
       
  1189 						if (prefix.Compare(KDnsNonrecursive) == 0)
       
  1190 							{
       
  1191 							iQueryFlags &= ~KDnsModifier_RD;	// Reset recursive flag.
       
  1192 							}
       
  1193 						else if (cf.iQueryHack)
       
  1194 							{
       
  1195 							// Special Query
       
  1196 							iQueryIsSpecial = 1;
       
  1197 							TInt q = sizeof(KQueryExtension) / sizeof(KQueryExtension[0]);
       
  1198 							while (--q >= 0 && prefix.Compare(*KQueryExtension[q].iPrefix) != 0)
       
  1199 								/* NOTHING */;
       
  1200 							if (q < 0)
       
  1201 								{
       
  1202 								// Requested query is not supported
       
  1203 								QueryDone(KErrNotSupported);
       
  1204 								return;
       
  1205 								}
       
  1206 							iQueryStep = &KQueryExtension[q].iQuery;
       
  1207 							iQuerySteps = 1;
       
  1208 							}
       
  1209 						else
       
  1210 							{
       
  1211 							QueryDone(KErrNotSupported);
       
  1212 							return;
       
  1213 							}
       
  1214 						rec.iName.Delete(0,i+1);
       
  1215 						}
       
  1216 
       
  1217 					if (!iQueryIsSpecial)
       
  1218 						{
       
  1219 						// Standard GetByName
       
  1220 						if ((cf.iQueryOrder & KQueryOrder_PreferA) == 0)
       
  1221 							{
       
  1222 							iQueryStep = KGetByName1;
       
  1223 							iQuerySteps = sizeof(KGetByName1) / sizeof(KGetByName1[0]);
       
  1224 							}
       
  1225 						else
       
  1226 							{
       
  1227 							iQueryStep = KGetByName2;
       
  1228 							iQuerySteps = sizeof(KGetByName2) / sizeof(KGetByName2[0]);
       
  1229 							}
       
  1230 						// If query is to be limited to only one (either A or AAAA), do
       
  1231 						// the preferred query only (the first in the chosen list).
       
  1232 						if (cf.iQueryOrder & KQueryOrder_OneQuery)
       
  1233 							iQuerySteps = 1;
       
  1234 						}
       
  1235 #else
       
  1236 					const TInt i = rec.iName.Locate('?');
       
  1237 
       
  1238 					if (i < 0)
       
  1239 						{
       
  1240 						// Standard GetByName
       
  1241 						iQueryIsSpecial = 0;
       
  1242 						if ((cf.iQueryOrder & KQueryOrder_PreferA) == 0)
       
  1243 							{
       
  1244 							iQueryStep = KGetByName1;
       
  1245 							iQuerySteps = sizeof(KGetByName1) / sizeof(KGetByName1[0]);
       
  1246 							}
       
  1247 						else
       
  1248 							{
       
  1249 							iQueryStep = KGetByName2;
       
  1250 							iQuerySteps = sizeof(KGetByName2) / sizeof(KGetByName2[0]);
       
  1251 							}
       
  1252 						// If query is to be limited to only one (either A or AAAA), do
       
  1253 						// the preferred query only (the first in the chosen list).
       
  1254 						if (cf.iQueryOrder & KQueryOrder_OneQuery)
       
  1255 							iQuerySteps = 1;
       
  1256 						}
       
  1257 					else if (cf.iQueryHack)
       
  1258 						{
       
  1259 						// Special Query
       
  1260 						iQueryIsSpecial = 1;
       
  1261 						const TPtrC prefix = rec.iName.Left(i+1);
       
  1262 						TInt q = sizeof(KQueryExtension) / sizeof(KQueryExtension[0]);
       
  1263 						while (--q >= 0 && prefix.Compare(*KQueryExtension[q].iPrefix) != 0)
       
  1264 							/* NOTHING */;
       
  1265 						rec.iName.Delete(0,i+1);
       
  1266 						if (q < 0)
       
  1267 							{
       
  1268 							// Requested query is not supported
       
  1269 							QueryDone(KErrNotSupported);
       
  1270 							return;
       
  1271 							}
       
  1272 						iQueryStep = &KQueryExtension[q].iQuery;
       
  1273 						iQuerySteps = 1;
       
  1274 						}
       
  1275 					else
       
  1276 						{
       
  1277 						QueryDone(KErrNotSupported);
       
  1278 						return;
       
  1279 						}
       
  1280 #endif
       
  1281 					}
       
  1282 				}
       
  1283 				break;
       
  1284 			case KDnsRequestType_TDnsQuery:
       
  1285 				// Special Query
       
  1286 				iQueryIsSpecial = 1;
       
  1287 				iQueryIsAddr = 0;
       
  1288 				iQueryScope = KIp6AddrScopeNetwork;
       
  1289 				iSpecificQuery.iQType = EDnsQType(iBuffer().Query().Type());
       
  1290 				iQueryStep = &iSpecificQuery;
       
  1291 				iQuerySteps = 1;
       
  1292 #ifdef DND_DCM_EXTENSION
       
  1293 				if (iBuffer().Query().Type() == KDnsQTypeCacheClear)
       
  1294 					{
       
  1295 					TRAPD(err, iListener.HandleCommandL(EDndFlush));
       
  1296 					iQueryComplete = 1;	// "Next()" is not allowed!
       
  1297 					QueryDone(err);
       
  1298 					return;							
       
  1299 					}
       
  1300 #endif
       
  1301 				break;
       
  1302 			case KDnsRequestType_SetHostName:
       
  1303 				iQueryComplete = 1;	// "Next()" is not allowed (only needed for ret == KErrNone case)
       
  1304 				QueryDone(iDnsclient.SetHostName(iBuffer().iId, iBuffer().HostName()));
       
  1305 				return;
       
  1306 			case KDnsRequestType_GetHostName:
       
  1307 				{
       
  1308 				const TInt ret = iDnsclient.GetHostName(iBuffer().iId, iBuffer().HostName(), *this);
       
  1309 				if (ret <=  0)
       
  1310 					{
       
  1311 					iQueryComplete = 1;	// "Next()" is not allowed (only needed for ret == KErrNone case)
       
  1312 					QueryDone(ret);		// GetHostName completed, we are done!
       
  1313 					}
       
  1314 				// GetHostName is pending on uniquenes test (ret == 1)
       
  1315 				return;
       
  1316 				}
       
  1317 			default:
       
  1318 				QueryDone(KErrNotSupported);
       
  1319 				return;
       
  1320 			}
       
  1321 		//
       
  1322 		// Setup NS source (now fixed, make configurable later)
       
  1323 		//
       
  1324 		iSourceList = KSourceOrder;
       
  1325 		iSourceCount = sizeof(KSourceOrder) / sizeof(KSourceOrder[0]);
       
  1326 		NextSource();
       
  1327 		}
       
  1328 	}
       
  1329 
       
  1330 // Only used for GetHostName
       
  1331 void CDndResolver::ReplyCallback(const TInt aResult)
       
  1332 	{
       
  1333 	iBuffer = iCurrentQuery;
       
  1334 	QueryDone(aResult);
       
  1335 	}
       
  1336 
       
  1337 //
       
  1338 //
       
  1339 
       
  1340 TQuerySession::TQuerySession() : iTimeout(TQuerySessionTimeoutLinkage::Timeout)
       
  1341 	{
       
  1342 	}
       
  1343 
       
  1344 // TQuerySession::Init
       
  1345 // *******************
       
  1346 void TQuerySession::Init(CDndResolver *const aResolver)
       
  1347 	/**
       
  1348 	* Initialize structure.
       
  1349 	*
       
  1350 	* A separate Init is required, because arrays cannot have non-defaulf
       
  1351 	* constructors. Need to patch the iResolver link "manually".
       
  1352 	*/
       
  1353 	{
       
  1354 	iResolver = aResolver;
       
  1355 	// ...for other members, the default constructor is sufficient
       
  1356 	}
       
  1357 
       
  1358 
       
  1359 // TQuerySession::Open
       
  1360 // *******************
       
  1361 void TQuerySession::Open()
       
  1362 	/**
       
  1363 	* Activate a query session.
       
  1364 	*
       
  1365 	* Assume CDndResolver::iCurrentQuery holds the request from the client.
       
  1366 	* Establish a session with the DNS protocol provides and initialize
       
  1367 	* it with the current question (NewQuery).
       
  1368 	*/
       
  1369 	{
       
  1370 	iSession = iResolver->iDnsclient.OpenSession(this);
       
  1371 	if (iSession == NULL)
       
  1372 		{
       
  1373 		// Cannot allocate a session
       
  1374 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- OUT OF DNS SESSIONS!"),
       
  1375 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1376 		iStatus = KErrNoMemory;
       
  1377 		}
       
  1378 	else
       
  1379 		{
       
  1380 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- Assigned DNS session [%u]"),
       
  1381 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, (TInt)iSession->Instance()));
       
  1382 		// ..if NewQuery returns an error, it will be the result of the query. Otherwise
       
  1383 		// use the KErrEof as initial value.
       
  1384 		iStatus = iSession->NewQuery(iResolver->iCurrentQuery(), iResolver->iSourceNow, iResolver->iQueryFlags);
       
  1385 		if (iStatus == KErrNone)
       
  1386 			iStatus = KErrEof;	// No content yet.
       
  1387 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1388 		else // in case the Query String is UTF-16 encoded
       
  1389 			{
       
  1390 			iResolver->QueryDone(iStatus);
       
  1391 			}
       
  1392 #endif //SYMBIAN_DNS_PUNYCODE
       
  1393 		}
       
  1394 	}
       
  1395 
       
  1396 // TQuerySession::SetTimer
       
  1397 // ***********************
       
  1398 void TQuerySession::SetTimer(TUint aTimeout)
       
  1399 	/**
       
  1400 	* Request a Timeout() call after the specied number of seconds.
       
  1401 	*/
       
  1402 	{
       
  1403 	LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- set timeout = %ds"),
       
  1404 		iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, (TInt)aTimeout));
       
  1405 	iResolver->iControl.Timer().Set(iTimeout, aTimeout);
       
  1406 	}
       
  1407 
       
  1408 // TQuerySession::Start
       
  1409 // ********************
       
  1410 TBool TQuerySession::Start(EDnsQType aQType)
       
  1411 	/**
       
  1412 	* Start the query process for a specific query type.
       
  1413 	*
       
  1414 	* @param aQType The query type (A, AAAA, MX, etc.)
       
  1415 	*/
       
  1416 	{
       
  1417 	iQType = aQType;
       
  1418 	LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- Start"),
       
  1419 		iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1420 	iServerCount = 1;
       
  1421 	iQueryRetry = 0;
       
  1422 	iQueryTimeouts = 0;
       
  1423 
       
  1424 	if (!iSession)
       
  1425 		return FALSE;
       
  1426 	
       
  1427 	iStatus = KErrEof;
       
  1428 
       
  1429 	if (iSession->PickDefaultServer())
       
  1430 		{
       
  1431 		SendDnsQuery();
       
  1432 		return TRUE;
       
  1433 		}
       
  1434 	return FALSE;
       
  1435 	}
       
  1436 
       
  1437 // TQuerySession::Cancel
       
  1438 // *********************
       
  1439 void TQuerySession::Cancel()
       
  1440 	/**
       
  1441 	* Cancel and stop all activity (if any) with this session.
       
  1442 	*
       
  1443 	* This cancels set timers and any DNS queries that are in
       
  1444 	* progress.
       
  1445 	*/
       
  1446 	{
       
  1447 	iTimeout.Cancel();
       
  1448 
       
  1449 	if (!iSession)
       
  1450 		return;
       
  1451 
       
  1452 	iSession->CancelQuery();
       
  1453 	if (iStatus == KRequestPending)
       
  1454 		{
       
  1455 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- CANCELED"),
       
  1456 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1457 		iStatus = KErrCancel;
       
  1458 		}
       
  1459 	}
       
  1460 
       
  1461 
       
  1462 // TQuerySession::Close
       
  1463 // ********************
       
  1464 void TQuerySession::Close()
       
  1465 	/**
       
  1466 	* Close session.
       
  1467 	*
       
  1468 	* First calls Cancel() to call all activity, and then also
       
  1469 	* closes the session with DNS protocol provider.
       
  1470 	*/
       
  1471 	{
       
  1472 	iPendingQuery = 0;	// Cancel pending queries too!
       
  1473 	Cancel();
       
  1474 	if (!iSession)
       
  1475 		return;
       
  1476 	iSession->Close();
       
  1477 	LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- DNS [%u] closed"),
       
  1478 		iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, (TInt)iSession));
       
  1479 	iSession = NULL;
       
  1480 	}
       
  1481 
       
  1482 
       
  1483 // TQuerySession::RecvReply
       
  1484 // ***********************
       
  1485 void TQuerySession::ReplyCallback(TInt aErr)
       
  1486 	/**
       
  1487 	* Callback from DNS client.
       
  1488 	*
       
  1489 	* DNS client has completed something.
       
  1490 	*
       
  1491 	* @param aErr The completion result or some notify.
       
  1492 	*/
       
  1493 	{
       
  1494 	if (iStatus != KRequestPending)
       
  1495 		{
       
  1496 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- RecvReply(%d) Ignore event"),
       
  1497 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, aErr));
       
  1498 		return;	// Unexpected event, ignore!
       
  1499 		}
       
  1500 
       
  1501 	if (aErr > 0)
       
  1502 		{
       
  1503 		// Notify Messages, just ignore if not recognised.
       
  1504 		if (aErr == KDnsNotify_QUERY_SENT)
       
  1505 			{
       
  1506 			if (iWaitingQuerySent)
       
  1507 				{
       
  1508 				iWaitingQuerySent = 0;	// got it...
       
  1509 				LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- RecvReply(%d) Query Sent"),
       
  1510 					iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, aErr));
       
  1511 				SetTimer(iQueryTimeoutValue);
       
  1512 				}
       
  1513 			}
       
  1514 		else if (aErr == KDnsNotify_HAVE_SERVERLIST)
       
  1515 			{
       
  1516 			// Currently does nothing with this.
       
  1517 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- RecvReply(%d) Has serverlist"),
       
  1518 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, aErr));
       
  1519 			}
       
  1520 		else if (aErr == KDnsNotify_USING_TCP)
       
  1521 			{
       
  1522 			iQueryRetry = iResolver->iQueryStepRetries;
       
  1523 			iQueryTimeoutValue = iResolver->iQueryStepMaxTime;
       
  1524 			iWaitingQuerySent = 0;
       
  1525 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- RecvReply(%d) Query using TCP, disable retransmit"),
       
  1526 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, aErr));
       
  1527 			SetTimer(iQueryTimeoutValue);
       
  1528 			}
       
  1529 		}
       
  1530 	else if (aErr != KErrNone && (aErr > KErrDndNameNotFound || aErr < KErrDndServerUnusable))
       
  1531 		{
       
  1532 		// The error is not query specific DND error code, assume it is
       
  1533 		// something general and abort the query totally.
       
  1534 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- RecvReply(%d) Query completed"),
       
  1535 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, aErr));
       
  1536 		iResolver->QueryDone(aErr);
       
  1537 		}
       
  1538 	else
       
  1539 		{
       
  1540 		iStatus = aErr;
       
  1541 		iTimeout.Cancel();
       
  1542 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- RecvReply(%d) Handle event"),
       
  1543 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, aErr));
       
  1544 		Event(FALSE);
       
  1545 		}
       
  1546 	}
       
  1547 
       
  1548 // TQuerySession::Timeout
       
  1549 // **********************
       
  1550 void TQuerySession::Timeout(const TTime &aNow)
       
  1551 	/**
       
  1552 	* No response from the DNS handler within specified time, handle timeout.
       
  1553 	*
       
  1554 	* @param aNow The current time
       
  1555 	*/
       
  1556 	{
       
  1557 	LOG(Log::Printf(_L("-->\tresolver[%d] SESSION %d QType=%d (%S) -- timeout start"),
       
  1558 		iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1559 	if (iWaitingQuerySent)
       
  1560 		{
       
  1561 		//
       
  1562 		// Don't wait forever, abort resolving if max setup time exceeded
       
  1563 		//
       
  1564 		const TDndConfigParameters &cf = iResolver->iControl.GetConfig();
       
  1565 		TTimeIntervalSeconds seconds;
       
  1566 		if (aNow.SecondsFrom(iResolver->iRequestTime, seconds) != KErrNone ||
       
  1567 			seconds.Int() > STATIC_CAST(TInt, cf.iSetupTime))
       
  1568 			{
       
  1569 			iStatus = KErrDndServerUnusable;
       
  1570 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- Timeout, max wait expired [%d > %d]: %d"),
       
  1571 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, seconds.Int(), cf.iSetupTime, iStatus));
       
  1572 			}
       
  1573 		else
       
  1574 			{
       
  1575 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- Timeout, has waited %ds [max %d]"),
       
  1576 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName, seconds.Int(), cf.iSetupTime));
       
  1577 			}
       
  1578 		}
       
  1579 	else
       
  1580 		{
       
  1581 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- timeout"),
       
  1582 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1583 		}
       
  1584 	// Note that Timeout alone does not touch the iStatus, nor does it
       
  1585 	// cancel the request, if any is active. It's up to Event to decide
       
  1586 	// on these issues.
       
  1587 	Event(TRUE);
       
  1588 	LOG(Log::Printf(_L("<--\tresolver[%d] SESSION %d QType=%d (%S) -- timeout exit"),
       
  1589 		iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1590 	}
       
  1591 
       
  1592 
       
  1593 // TQuerySession::Event
       
  1594 // ********************
       
  1595 void TQuerySession::Event(TBool aTimeOut)
       
  1596 	/**
       
  1597 	* Shared handling of session events: timeouts and DNS query completions.
       
  1598 	*
       
  1599 	* @param aTimeOut is TRUE, if this is a timeout event; and FALSE, if
       
  1600 	*			event caused by DNS completion.
       
  1601 	*/
       
  1602 	{
       
  1603 	const TDndConfigParameters &cf = iResolver->iControl.GetConfig();
       
  1604 
       
  1605 	// Handle events from DNS or timeout
       
  1606 	// *********************************
       
  1607 	// TIMEOUT or REPLY to a pending query has been received
       
  1608 	//
       
  1609 	const TBool server_unusable = (iStatus == KErrDndRefused || iStatus == KErrDndServerUnusable);
       
  1610 	if (!aTimeOut && !server_unusable)
       
  1611 		{
       
  1612 		// This query has been completed with some definite result, notify
       
  1613 		// the main resolver to handle the reply.
       
  1614 		//
       
  1615 		iResolver->GetNextAnswer();
       
  1616 		return;
       
  1617 		}
       
  1618 
       
  1619 
       
  1620 	if (iWaitingQuerySent && !server_unusable)
       
  1621 		{
       
  1622 		// Still waiting for the first query packet to be sent. Request a
       
  1623 		// resend attempt of the same query again (without counting it as
       
  1624 		// retry). This is a wait for getting interfaces up (normal timeouts
       
  1625 		// do not apply yet).
       
  1626 
       
  1627 		// Reload the query too (this is only sometimes needed with PTR
       
  1628 		// queries if the filter iLockId cannot be determined due to
       
  1629 		// missing interfaces. And only happens if query address was
       
  1630 		// without scope id.
       
  1631 		(void)iSession->NewQuery(iResolver->iCurrentQuery(), iResolver->iSourceNow, iResolver->iQueryFlags);
       
  1632 		SendDnsQuery();
       
  1633 		return;
       
  1634 		}
       
  1635 
       
  1636 	if (aTimeOut)
       
  1637 		iQueryTimeouts++;	// Timeout occurred while resolving the DNS Query
       
  1638 
       
  1639 
       
  1640 	// Careful with iStatus: if timeout occurs, it is probably KRequestPending.
       
  1641 	// Needs to be changed to something else, if GetNextAnswer is called (otherwise
       
  1642 	// it will think that there are pending query and may do nothing!)
       
  1643 	//
       
  1644 	if (cf.iSprayMode || iResolver->iSourceNow > 0 /* == multicast resolution mode */)
       
  1645 		{
       
  1646 		if (iWaitingAfterSpray)
       
  1647 			{
       
  1648 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- Delay after spray completed"),
       
  1649 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1650 			//
       
  1651 			// The delay after "spray" has expired, now start a new round (a retry)
       
  1652 			// (unless maximum retries has been reached)
       
  1653 			//
       
  1654 			iWaitingAfterSpray = 0;
       
  1655 			iQueryTimeouts = 0;
       
  1656 			(void)iSession->PickDefaultServer();
       
  1657 			iStatus = KErrTimedOut;
       
  1658 			iServerCount = 1;
       
  1659 			++iQueryRetry;
       
  1660 			if (iQueryRetry > iResolver->iQueryStepRetries)
       
  1661 				iResolver->GetNextAnswer();
       
  1662 			else
       
  1663 				SendDnsQuery();
       
  1664 			}
       
  1665 		else if (iSession->PickNewServer())
       
  1666 			{
       
  1667 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- More servers to spray"),
       
  1668 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1669 			//
       
  1670 			// Yet another server to spray, replicate query
       
  1671 			//
       
  1672 			iWaitingAfterSpray = 0;
       
  1673 			++iServerCount;
       
  1674 			SendDnsQuery();	// Replicate query to another server
       
  1675 			}
       
  1676 		else if (iQueryTimeouts > 0)
       
  1677 			{
       
  1678 			// All servers have been sprayed and at least one of them
       
  1679 			// has not answered, now wait maxtime - (servers * mintime),
       
  1680 			// before starting the next spraying round
       
  1681 			//
       
  1682 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- All servers sprayed, now wait results"),
       
  1683 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1684 			iWaitingAfterSpray = 1;
       
  1685 			const TInt maxtime = Max(iResolver->iQueryStepMinTime, iResolver->iQueryStepMaxTime / (iResolver->iQueryStepRetries+1));
       
  1686 			SetTimer(Max(iResolver->iQueryStepMinTime, maxtime - iResolver->iQueryStepMinTime * iServerCount));
       
  1687 			}
       
  1688 		else
       
  1689 			{
       
  1690 			LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- All servers replied not found"),
       
  1691 				iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1692 			// All servers sprayed, and none of the short spray timeouts expired
       
  1693 			// (make a heuristic GUESS, that all servers replied, but all were either
       
  1694 			// unusable or "skip not found" is active. Just goto to the next step or
       
  1695 			// return not found.
       
  1696 			iResolver->GetNextAnswer();
       
  1697 			}
       
  1698 		}
       
  1699 	else
       
  1700 		{
       
  1701 		++iQueryRetry;	// This is a true retry
       
  1702 		if (iQueryRetry > iResolver->iQueryStepRetries ||
       
  1703 			(server_unusable && !iSession->PickNewServer()))
       
  1704 			{
       
  1705 			iStatus = KErrTimedOut;
       
  1706 			iResolver->GetNextAnswer();// Activates next query step or returns not found.
       
  1707 			}
       
  1708 		else
       
  1709 			{
       
  1710 			iResolver->ProbeServers();	// ...keep probing for alternate servers in parallel (at each timeout)
       
  1711 			SendDnsQuery();
       
  1712 			}
       
  1713 		}
       
  1714 	}
       
  1715 
       
  1716 
       
  1717 // TQuerySession::SendDnsQuery
       
  1718 // ***************************
       
  1719 void TQuerySession::SendDnsQuery()
       
  1720 	/**
       
  1721 	* Activate a new DNS query to be sent.
       
  1722 	*/
       
  1723 	{
       
  1724 	if (iSendingQuery)
       
  1725 		{
       
  1726 		// Doing everyhing in callbacks forces extra work
       
  1727 		// to be done to prevent deep recursion...
       
  1728 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- NEW QUERY PENDING"),
       
  1729 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1730 
       
  1731 		iPendingQuery = 1;
       
  1732 		return;
       
  1733 		}
       
  1734 	// Create an UDP message to the DNS
       
  1735 	do
       
  1736 		{
       
  1737 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- SENDING DNS QUERY"),
       
  1738 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1739 		iStatus = KRequestPending;
       
  1740 		iSendingQuery = 1;		// ..to detect dangerous recursion
       
  1741 		iPendingQuery = 0;		// ..to detect that a new query should be sent
       
  1742 		iWaitingQuerySent = 1; // Mark: waiting for QUERY_SENT
       
  1743 		TRAPD(err, (void)iSession->DoQueryL(iResolver->iRequestTime, iQType));
       
  1744 		iSendingQuery = 0;
       
  1745 		if (err != KErrNone)
       
  1746 			{
       
  1747 			// Assume some serious error situation and forget about
       
  1748 			// possible pending query, cancel everything with error.
       
  1749 			iResolver->QueryDone(err);
       
  1750 			return;
       
  1751 			}
       
  1752 		}
       
  1753 	while (iPendingQuery);
       
  1754 
       
  1755 	if (iStatus == KRequestPending)
       
  1756 		{
       
  1757 		const TDndConfigParameters &cf = iResolver->iControl.GetConfig();
       
  1758 		const TUint maxtime = iResolver->iQueryStepMaxTime;
       
  1759 
       
  1760 		// Compute the timeout for the next query (starts ticking
       
  1761 		// when the packet has been sent (after QUERY_SENT)
       
  1762 		//
       
  1763 		if (cf.iSprayMode || iResolver->iSourceNow > 0)
       
  1764 			iQueryTimeoutValue = iResolver->iQueryStepMinTime;	// Send to all servers using mintime 
       
  1765 		else if (cf.iRetries == 0)
       
  1766 			iQueryTimeoutValue = maxtime;		// No retries, just single query
       
  1767 		else if (iQueryRetry == 0)
       
  1768 			iQueryTimeoutValue = iResolver->iQueryStepMinTime;	// This is the first send -- use min time
       
  1769 		else
       
  1770 			{
       
  1771 			// This a retransmission (divide the remaining time even with the retries)
       
  1772 			iQueryTimeoutValue = Max(iResolver->iQueryStepMinTime, (maxtime - iResolver->iQueryStepMinTime) / iResolver->iQueryStepRetries);
       
  1773 			}
       
  1774 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- WAITING FOR SEND"),
       
  1775 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1776 		// Setup "poll" timer, if the
       
  1777 		// DNS side does not send the QUERY_SENT notification.
       
  1778 		// (retry count is not incremented, so it will "poll"
       
  1779 		// as long as notification/reply arrives or user cancels
       
  1780 		// the resolving).
       
  1781 		if (iWaitingQuerySent)
       
  1782 			SetTimer(cf.iSetupPoll);
       
  1783 		}
       
  1784 	else
       
  1785 		{
       
  1786 		LOG(Log::Printf(_L("\tresolver[%d] SESSION %d QType=%d (%S) -- COMPLETED WITHIN"),
       
  1787 			iResolver->iId, iResolver->iCurrentQuery().iSession, (TInt)iQType, &iName));
       
  1788 		}
       
  1789 	}