tcpiputils/dnd/src/dns.cpp
changeset 0 af10295192d8
child 20 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 // dns.cpp - the main client module of the DNS.
       
    15 //
       
    16 
       
    17 #include <e32math.h>
       
    18 #include <in_sock.h>
       
    19 #include <in6_opt.h>
       
    20 #include "dns.h"
       
    21 #include "dnd.hrh"		// EDndDump
       
    22 #include <networking/dnd_err.h>
       
    23 #include "engine.h"
       
    24 #include "servers.h"
       
    25 #include "cache.h"
       
    26 #include "inet6log.h"
       
    27 #ifdef LLMNR_ENABLED
       
    28 #	include "llmnrresponder.h"
       
    29 #endif
       
    30 #include "dnd_ini.h"
       
    31 
       
    32 #ifdef EXCLUDE_SYMBIAN_DNS_PUNYCODE
       
    33 #undef SYMBIAN_DNS_PUNYCODE
       
    34 #endif //EXCLUDE_SYMBIAN_DNS_PUNYCODE
       
    35 
       
    36 class CDnsService : public CDndDnsclient
       
    37 	{
       
    38 public:
       
    39 	CDnsService(CDndEngine &aControl, MDnsServerManager &aServerManager) : CDndDnsclient(aControl, aServerManager) {}
       
    40 	void ConstructL();
       
    41 	~CDnsService();
       
    42 	virtual void ConfigurationChanged();
       
    43 
       
    44 	TInt SetHostName(TUint32 aId, const THostName &aName);
       
    45 	TInt GetHostName(TUint32 aId, THostName &aName, MDnsResolver &aCallback);
       
    46 
       
    47 	TInt GetByAddress(TUint32 aId, const TInetAddr &aAddr, TInt aNext, THostName &aName);
       
    48 	TInt GetByName(TUint32 aId, const THostName &aName, TInt aNext, TInetAddr &aAddr);
       
    49 private:
       
    50 #ifdef LLMNR_ENABLED
       
    51 	CDndLlmnrResponder *iLlmnrResponder; //< Pointer to the LLMNR responder object
       
    52 #endif
       
    53 	TUint32 GetNetId(TUint32 aIndex);
       
    54 	TInetAddressInfo *GetAddressList(TInt &aN);
       
    55 	};
       
    56 
       
    57 
       
    58 void CDnsService::ConstructL()
       
    59 	{
       
    60 	CDndDnsclient::ConstructL();
       
    61 #ifdef LLMNR_ENABLED
       
    62 	iLlmnrResponder = new (ELeave) CDndLlmnrResponder(iControl, iServerManager, iHostNames);
       
    63 	iLlmnrResponder->ConstructL();
       
    64 #endif
       
    65 	}
       
    66 
       
    67 CDnsService::~CDnsService()
       
    68 	{
       
    69 #ifdef LLMNR_ENABLED
       
    70 	delete iLlmnrResponder;
       
    71 #endif
       
    72 	}
       
    73 	
       
    74 
       
    75 void CDnsService::ConfigurationChanged()
       
    76 	{
       
    77 #ifdef LLMNR_ENABLED
       
    78 	iLlmnrResponder->ConfigurationChanged();
       
    79 #endif
       
    80 	}
       
    81 //
       
    82 // Gateway hostname processing to the responder
       
    83 //
       
    84 TInt CDnsService::SetHostName(TUint32 aId, const THostName &aName)
       
    85 	{
       
    86 	const TInt res = iHostNames.Map(aId, aName);
       
    87 #ifdef LLMNR_ENABLED
       
    88 	return res == KErrNone ? iLlmnrResponder->SetHostName(aId, iHostNames.Find(aId)) : res;
       
    89 #else
       
    90 	return res;
       
    91 #endif
       
    92 	}
       
    93 
       
    94 TInt CDnsService::GetHostName(TUint32 aId, THostName &aName, MDnsResolver &aCallback)
       
    95 	{
       
    96 	aName = iHostNames.Find(aId);
       
    97 #ifdef LLMNR_ENABLED
       
    98 	return iLlmnrResponder->GetHostName(aId, aCallback);
       
    99 #else
       
   100 	(void)aCallback;
       
   101 	return KErrNone;
       
   102 #endif
       
   103 	}
       
   104 
       
   105 
       
   106 
       
   107 TUint32 CDnsService::GetNetId(TUint32 aIndex)
       
   108 	{
       
   109 	TPckgBuf<TSoInetIfQuery> opt;
       
   110 	opt().iIndex = aIndex;
       
   111 	return iControl.iSocket.GetOpt(KSoInetIfQueryByIndex, KSolInetIfQuery, opt) == KErrNone
       
   112 		? opt().iZone[15] : 0;
       
   113 	}
       
   114 
       
   115 TInetAddressInfo *CDnsService::GetAddressList(TInt &aN)
       
   116 	/**
       
   117 	* Returns a list of all current addresses.
       
   118 	*
       
   119 	* @retval aN	The number of addresses (if return is non-NULL).
       
   120 	* @return		The address list, or NULL if not available.
       
   121 	*
       
   122 	* The returned address list must be freed by the caller
       
   123 	* as "delete[] list".
       
   124 	*/
       
   125 	{
       
   126 	TPtr8 empty(NULL, 0);
       
   127 	aN = iControl.iSocket.GetOpt(KSoInetAddressInfo, KSolInetIfQuery, empty);
       
   128 	if (aN <= 0)
       
   129 		return NULL;
       
   130 	TInetAddressInfo *p = new TInetAddressInfo[aN];
       
   131 	if (p == NULL)
       
   132 		return NULL;	// No memory available.
       
   133 	TPtr8 opt((TUint8 *)p, aN*sizeof(TInetAddressInfo));
       
   134 	aN = iControl.iSocket.GetOpt(KSoInetAddressInfo, KSolInetIfQuery, opt);
       
   135 	if (aN < 0)
       
   136 		aN = 0;
       
   137 	else
       
   138 		aN = opt.Length() / (TInt)sizeof(TInetAddressInfo);
       
   139 	return p;
       
   140 	}
       
   141 
       
   142 
       
   143 TInt CDnsService::GetByAddress(TUint32 /*aId*/, const TInetAddr &aAddr, TInt /*aNext*/, THostName &aName)
       
   144 	/**
       
   145 	* Returns the local hostname, if address is my own.
       
   146 	*/
       
   147 	{
       
   148 	TPckgBuf<TSoInetIfQuery> opt;
       
   149 	opt().iSrcAddr = aAddr;
       
   150 	if (iControl.iSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, opt) != KErrNone)
       
   151 		return KErrNotFound;
       
   152 	aName = iHostNames.Find(opt().iZone[15]);	// Locate hostname for network id.
       
   153 	return (aName.Length() > 0) ? KErrNone : KErrNotFound;
       
   154 	}
       
   155 
       
   156 TInt CDnsService::GetByName(TUint32 aId, const THostName &aName, TInt /*aNext*/, TInetAddr &aAddr)
       
   157 	/**
       
   158 	* Returns one of my own addresses, if the hostname is local.
       
   159 	*/
       
   160 	{
       
   161 	const TDesC &name = iHostNames.Find(aId);
       
   162 	if (aName.Length() > 0 && name.CompareF(aName) != 0)
       
   163 		return KErrNotFound;	// The query name is not a local host.
       
   164 	//
       
   165 	// Locate a local addres from some interface within the specific network.
       
   166 	//
       
   167 	TInt N;
       
   168 	TInetAddressInfo *list = GetAddressList(N);
       
   169 	if (list == NULL)
       
   170 		return KErrNotFound;
       
   171 
       
   172 	TUint32 iface = 0;
       
   173 	TUint32 netid = 0;
       
   174 	TInt scope = -1;
       
   175 	TInt best = 0;
       
   176 	for (TInt i = 0; i < N; ++i)
       
   177 		{
       
   178 		if (list[i].iState != TInetAddressInfo::EAssigned)
       
   179 			continue;
       
   180 		if (list[i].iInterface != iface)
       
   181 			{
       
   182 				iface = list[i].iInterface;
       
   183 				netid = GetNetId(iface);
       
   184 			}
       
   185 		if (netid != aId)
       
   186 			continue;	// Not this address.
       
   187 		if (list[i].iAddress.Scope() > scope)
       
   188 			{
       
   189 			scope = list[i].iAddress.Scope();
       
   190 			best = i;
       
   191 			}
       
   192 		}
       
   193 	aAddr.SetAddress(list[best].iAddress);
       
   194 	aAddr.SetScope(list[best].iScopeId);
       
   195 	delete[] list;
       
   196 	return scope < 0 ? KErrNotFound : KErrNone;
       
   197 	}
       
   198 
       
   199 //
       
   200 //
       
   201 
       
   202 CDndDnsclient *CDndDnsclient::NewL(CDndEngine &aControl, MDnsServerManager &aServerManager)
       
   203 	{
       
   204 	LOG(Log::Printf(_L("CDndDnsclient::NewL()")));
       
   205 
       
   206 	CDnsService *const dns = new (ELeave) CDnsService(aControl, aServerManager);
       
   207 	CleanupStack::PushL(dns);
       
   208 	dns->ConstructL();
       
   209 	CleanupStack::Pop();
       
   210 	return dns;
       
   211 	}
       
   212 
       
   213 CDndDnsclient::CDndDnsclient(CDndEngine &aControl, MDnsServerManager &aServerManager)
       
   214 	: CDnsSocket(aControl.GetConfig().iEDNS0), iControl(aControl), iServerManager(aServerManager)
       
   215 	{
       
   216 	}
       
   217 
       
   218 void CDndDnsclient::ConstructL()
       
   219 	{
       
   220 	LOG(Log::Printf(_L("CDndDnsclient::ConstructL() size=%d"), (TInt)sizeof(*this)));
       
   221 	CDnsSocket::ConstructL();
       
   222 
       
   223 	iCache = new (ELeave) CDndCache();
       
   224 	iCache->ConstructL();
       
   225 
       
   226 	TPtrC localhost;
       
   227 	if(iControl.FindVar(DND_INI_HOST, DND_INI_HOSTNAME, localhost))
       
   228 		(void)iHostNames.Reset(localhost);
       
   229 	else
       
   230 		(void)iHostNames.Reset(KDndIni_Hostname);
       
   231 	}
       
   232 
       
   233 
       
   234 
       
   235 
       
   236 void CDndDnsclient::HandleCommandL(TInt aCommand)
       
   237 	{
       
   238 #ifdef _LOG
       
   239 	switch(aCommand)
       
   240 		{
       
   241 		case EDndDump:
       
   242 			if (iCache)
       
   243 				iCache->Dump(iControl);
       
   244 			break;
       
   245 		default:
       
   246 			break;
       
   247 		}
       
   248 #endif
       
   249 	if (aCommand == EDndFlush)
       
   250 		iCache->Flush();
       
   251 	}
       
   252 
       
   253 CDndDnsclient::~CDndDnsclient()
       
   254 	{
       
   255 	DeactivateSocket();
       
   256 
       
   257 	// Just to be sure, cancel server list notifys (if any)
       
   258 	// (this means that SERVER MANAGER MUST NOT BE DELETED
       
   259 	// before this object!)
       
   260 	for (TUint i = 0; i < KDndNumRequests; i++)
       
   261 		iServerManager.CloseList(iDndReqData[i].iFilter);
       
   262 	delete iCache;
       
   263 	}
       
   264 
       
   265 // CDndDnsclient::CheckAddress
       
   266 // ***************************
       
   267 TInt CDndDnsclient::CheckAddress(const TInetAddr &aDestination)
       
   268 	{
       
   269 	TPckgBuf<TSoInetIfQuery> opt;
       
   270 	opt().iDstAddr = aDestination;
       
   271 	
       
   272 	const TInt err = iControl.iSocket.GetOpt(KSoInetIfQueryByDstAddr, KSolInetIfQuery, opt);
       
   273 	if (err == KErrNone && TInetAddr::Cast(opt().iSrcAddr).IsUnspecified())
       
   274 		return KErrNotFound;	// No route or source address.
       
   275 	return err;
       
   276 	}
       
   277 
       
   278 
       
   279 
       
   280 // TDndReqData::PickDefaultServer
       
   281 // ********************************
       
   282 TBool TDndReqData::PickDefaultServer()
       
   283 	{
       
   284 	TInetAddr tmp;
       
   285 	TBool ret = FALSE;
       
   286 
       
   287 	if (iCurrentServer == 0)
       
   288 		ret = iOwner->iServerManager.OpenList(iFilter, this) > 0;
       
   289 	iOwner->iCache->GetServerAddress(iOwner->iServerManager.NameSpace(iFilter, iCurrentServer), tmp);
       
   290 	iFilter.iServerId = iOwner->iServerManager.ServerId(tmp);
       
   291 	iCurrentServer = iOwner->iServerManager.Next(iFilter, 0);
       
   292 #ifdef _LOG
       
   293 	if (iCurrentServer)
       
   294 		Log::Printf(_L("\t\tDNS session [%u] default nameserver (id=%d) assigned"), (TInt)this, (TInt)iCurrentServer);
       
   295 	else
       
   296 		Log::Printf(_L("\t\tDNS session [%u] no nameservers available for this session"), (TInt)this);
       
   297 #endif
       
   298 	return ret || iCurrentServer != 0;
       
   299 	}
       
   300 
       
   301 
       
   302 // TDndReqData::PickNewServer
       
   303 // ****************************
       
   304 TBool TDndReqData::PickNewServer()
       
   305 	{
       
   306 	if (iCurrentServer == 0)
       
   307 		iOwner->iServerManager.BuildServerList();
       
   308 	iCurrentServer = iOwner->iServerManager.Next(iFilter, iCurrentServer);
       
   309 #ifdef _LOG
       
   310 	if (iCurrentServer)
       
   311 		Log::Printf(_L("\t\tDNS session [%u] next nameserver (id=%d) assigned"), (TInt)this, (TInt)iCurrentServer);
       
   312 	else
       
   313 		Log::Printf(_L("\t\tDNS session [%u] next, no alternate nameservers to assign"), (TInt)this);
       
   314 #endif
       
   315 	return iCurrentServer != 0;
       
   316 	}
       
   317 
       
   318 void TDndReqData::ServerListComplete(const TDnsServerFilter &aFilter, TInt aResult)
       
   319 	{
       
   320 	if (&aFilter == &iFilter)
       
   321 		{
       
   322 		iCurrentServer = iOwner->iServerManager.Next(iFilter, 0);
       
   323 		if (iIsReqPending)
       
   324 			{
       
   325 			if (aResult == KErrNone)
       
   326 				{
       
   327 				if (PickDefaultServer())
       
   328 					{
       
   329 					iOwner->ReSend(*this);
       
   330 					aResult = KDnsNotify_HAVE_SERVERLIST;
       
   331 					}
       
   332 				else
       
   333 					aResult = KErrDndServerUnusable;
       
   334 				}
       
   335 			SendResponse(aResult);
       
   336 			}
       
   337 		}
       
   338 	}
       
   339 
       
   340 
       
   341 // CDndDnsclient::OpenSession
       
   342 // **************************
       
   343 /**
       
   344 // A session is internally represented by a TDndReqData. Find an unused
       
   345 // entry and assign it. Unused entry is recognized by it having no
       
   346 // callback function (= NULL).
       
   347 */
       
   348 MDnsSession *CDndDnsclient::OpenSession(MDnsResolver *const aCallback)
       
   349 	{
       
   350 	TUint i;
       
   351 	//
       
   352 	// Locate available TDndReqData entry...
       
   353 	//
       
   354 	for (i = 0;; ++i)
       
   355 		{
       
   356 		if (i >= KDndNumRequests)
       
   357 			return NULL;	// No "sessions" available
       
   358 		// For now, assume the slot is available, if no callback has been installed
       
   359 		if (iDndReqData[i].iCallback == NULL)
       
   360 			break;
       
   361 		}
       
   362 	TDndReqData &rq = iDndReqData[i];
       
   363 	rq.iCallback = aCallback;
       
   364 	rq.iOwner = this;
       
   365 	iActivityCount++;	// Count each open session as "activity".
       
   366 	return &rq;
       
   367 	}
       
   368 
       
   369 
       
   370 void CDndDnsclient::Error(const TInetAddr &aServer, TInt /*aError*/)
       
   371 	{
       
   372 	const TUint server_id = iServerManager.ServerId(aServer);
       
   373 	if (server_id == 0)
       
   374 		return;		// -- nothing to do, address not registered as a server
       
   375 
       
   376 	//
       
   377 	// Try to notify all sessions currently using this server
       
   378 	//
       
   379 	for (TUint i = 0; i < KDndNumRequests; ++i)
       
   380 		{
       
   381 		TDndReqData &rq = iDndReqData[i];
       
   382 		// For now, assume the slot is in used, if callback has been installed
       
   383 		if (rq.iCallback == NULL)
       
   384 			continue;
       
   385 		if (rq.iCurrentServer == server_id)
       
   386 			rq.SendResponse(KErrDndServerUnusable);
       
   387 		}
       
   388 	}
       
   389 
       
   390 
       
   391 
       
   392 // TDndReqData::Close
       
   393 // ******************
       
   394 void TDndReqData::Close()
       
   395 	{
       
   396 	CancelQuery();
       
   397 	iCallback = NULL;
       
   398 	if (iRecord)
       
   399 		{
       
   400 		iRecord->Unlock(this);
       
   401 		iRecord = NULL;
       
   402 		}
       
   403 	iOwner->iServerManager.CloseList(iFilter);
       
   404 	// If this was the last active session, then
       
   405 	// cancel all requests 
       
   406 	ASSERT(iOwner->iActivityCount > 0);
       
   407 	if (--iOwner->iActivityCount == 0)
       
   408 		iOwner->DeactivateSocket();
       
   409 	}
       
   410 
       
   411 // TDndReqData::NewQuery
       
   412 // ***********************
       
   413 TInt TDndReqData::NewQuery(const TDnsMessage &aQuery, TDnsServerScope aServerScope, TUint32 aFlags)
       
   414 	{
       
   415 	iIsReqPending = FALSE;
       
   416 	iIsNewQuery = TRUE;
       
   417 	iIsUsingTCP = 0;
       
   418 	iQdCount = 1;
       
   419 	iFlags = aFlags;
       
   420 	iFilter.iServerScope = aServerScope;
       
   421 	iFilter.iServerId = 0;
       
   422 	iNetworkId = aQuery.iId;  // Get the networkId information from the Query.
       
   423 
       
   424 #ifdef SYMBIAN_DNS_PUNYCODE
       
   425 	if( (aQuery.iScope & 0x80) == 0x80 )
       
   426 		{
       
   427 		iIdnEnabled = 1;
       
   428 		iQuestion.EnableIdn(ETrue);
       
   429 		}
       
   430 	else 
       
   431 		{
       
   432 		iIdnEnabled = 0;
       
   433 		iQuestion.EnableIdn(EFalse);
       
   434 		}
       
   435 #endif //SYMBIAN_DNS_PUNYCODE
       
   436 
       
   437 	switch (aQuery.iType)
       
   438 		{
       
   439 		case KDnsRequestType_GetByName:
       
   440 		case KDnsRequestType_GetByAddress:
       
   441 			{
       
   442 			const TNameRecord &query = aQuery.NameRecord();
       
   443 
       
   444 			if (aQuery.iType == KDnsRequestType_GetByName)
       
   445 				{
       
   446 				iFilter.iLockId = aQuery.iId;
       
   447 				iFilter.iLockType = KIp6AddrScopeNetwork;
       
   448 #ifdef SYMBIAN_DNS_PUNYCODE
       
   449 				TInt err = iQuestion.SetName(query.iName);
       
   450 				if( err != KErrNone)
       
   451 					{
       
   452 					return err;
       
   453 					}
       
   454 #else
       
   455 				iQuestion.SetName(query.iName);
       
   456 #endif // SYMBIAN_DNS_PUNYCODE
       
   457 				}
       
   458 			else
       
   459 				{
       
   460 				iOwner->iServerManager.LockByAddress(TInetAddr::Cast(query.iAddr), aQuery.iId, iFilter);
       
   461 #ifdef SYMBIAN_DNS_PUNYCODE
       
   462 				TInt err = iQuestion.SetName(TInetAddr::Cast(query.iAddr));
       
   463 				if( err != KErrNone)
       
   464 					{
       
   465 					return err;
       
   466 					}
       
   467 #else
       
   468 				iQuestion.SetName(TInetAddr::Cast(query.iAddr));
       
   469 #endif // SYMBIAN_DNS_PUNYCODE
       
   470 				}
       
   471 			}
       
   472 			break;
       
   473 		case KDnsRequestType_TDnsQuery:
       
   474 			{
       
   475 			const TDnsQuery &query = aQuery.Query();
       
   476 			iQuestion.Copy(query.Data());
       
   477 			iFilter.iLockId = aQuery.iId;
       
   478 			iFilter.iLockType = KIp6AddrScopeNetwork;
       
   479 			}
       
   480 			break;
       
   481 		default:
       
   482 			return KErrNotSupported;
       
   483 		}
       
   484 	iCurrentServer = 0;
       
   485 	//
       
   486 	// For forward query, the Scope identifier of the aQuery.iAddr is the network id
       
   487 	// For pointer query, if the address is not of network scope, then need to find
       
   488 	// the network id based on the scope id... (fix later). -- msa
       
   489 
       
   490 	iOpcode = EDnsOpcode_QUERY;		// Only EStandard supported! (EInverse is not same as PTR query!!!)
       
   491 	if (iRecord)
       
   492 		{
       
   493 		iRecord->Unlock(this);
       
   494 		iRecord = NULL;
       
   495 		}
       
   496 	return KErrNone;
       
   497 	}
       
   498 
       
   499 
       
   500 // TDndReqData::CancelQuery
       
   501 // **************************
       
   502 void TDndReqData::CancelQuery()
       
   503 	{
       
   504 	iIsReqPending = FALSE;
       
   505 	Cancel();
       
   506 	iOwner->iServerManager.CloseList(iFilter);
       
   507 	}
       
   508 
       
   509 
       
   510 // TDndReqData::DoNext
       
   511 // *********************
       
   512 /**
       
   513 // @retval aReply	returns the requested Resource Record value, if KErrNone return
       
   514 // @param aNext		the index of the value to be returned. 0 is the index of the first value
       
   515 // @returns
       
   516 //	@li	KErrNotFound, if there is no value at specified index
       
   517 //	@li	KErrDndCache, if the reply from DNS stored in cache was corrupt
       
   518 //	@li	KErrNone, if value successfully returned
       
   519 */
       
   520 TInt TDndReqData::DoNext(TDnsMessageBuf &aReply, TInt aNext) const
       
   521 	{
       
   522 	if (iRecord == NULL)
       
   523 		return KErrNotFound;
       
   524 	TInt ret = iRecord->ErrorCode();
       
   525 	if (ret < 0)
       
   526 		return ret;	// No usable record present
       
   527 
       
   528 	TDndRR tempRR(iRecord->Reply());
       
   529 #ifdef SYMBIAN_DNS_PUNYCODE
       
   530 		tempRR.iIdnEnabled = TBool(iIdnEnabled);
       
   531 #endif //SYMBIAN_DNS_PUNYCODE
       
   532 
       
   533 	const TInet6HeaderDNS &hdr = iRecord->Header();
       
   534 	TInt answerCount = hdr.ANCOUNT();
       
   535 
       
   536 	ret = tempRR.FindRR(iRecord->AnswerOffset(), answerCount, iQuestion.QType(), iQuestion.QClass(), aNext);
       
   537 	if (ret < 0)
       
   538 		{
       
   539 		if (ret == KErrDndCache)
       
   540 			iRecord->Invalidate();
       
   541 		return ret;
       
   542 		}
       
   543 
       
   544 	TInetAddr *addr = NULL;
       
   545 
       
   546 	switch (aReply().iType)
       
   547 		{
       
   548 		case KDnsRequestType_GetByName:
       
   549 		case KDnsRequestType_GetByAddress:
       
   550 			{
       
   551 			TNameRecord &reply = aReply().NameRecord();
       
   552 			aReply.SetLength(aReply().HeaderSize() + sizeof(reply));
       
   553 			if (hdr.AA())
       
   554 				reply.iFlags |= EDnsAuthoritive;
       
   555 			ret = GetResponse(tempRR, reply);
       
   556 			reply.iFlags |= EDnsServer | (iIsFromCache ? EDnsCache : 0);
       
   557 			addr = &TInetAddr::Cast(reply.iAddr);
       
   558 			break;
       
   559 			}
       
   560 #ifndef NO_DNS_QUERY_SUPPORT
       
   561 		case KDnsRequestType_TDnsQuery:
       
   562 			ret = tempRR.GetResponse(aReply, &addr);
       
   563 			break;
       
   564 #endif
       
   565 		default:
       
   566 			return KErrNotSupported;
       
   567 		}
       
   568 	if (ret < 0)
       
   569 		return ret;		// Some error detected!
       
   570 
       
   571 	if (addr)
       
   572 		{
       
   573 		// Reply contains a TInetAddr. This needs some special processing
       
   574 
       
   575 		// Supplement IPv6 addresses with the scope value
       
   576 		// (Should do the same with IPv4 after converting to IPv4 mapped?)
       
   577 		if (addr->Family() == KAfInet)
       
   578 			addr->ConvertToV4Mapped();
       
   579 		if (addr->Family() == KAfInet6)
       
   580 			{
       
   581 			const TInt scope_level = addr->Ip6Address().Scope();
       
   582 
       
   583 			// Add the scope id only for addresses with larger than node
       
   584 			// local scope (this leaves the scope id as zero, if a loopback
       
   585 			// address is returned from the name server (The id of the node
       
   586 			// local scope is the interface index and non-zero value would
       
   587 			// bind loopback destination to real interface instead of internal
       
   588 			// loopback interface).
       
   589 			if (scope_level > KIp6AddrScopeNodeLocal)
       
   590 				addr->SetScope(iOwner->iServerManager.Scope(iRecord->Server(), *addr));
       
   591 
       
   592 #ifdef LLMNR_ENABLED
       
   593 			if(iOwner->iControl.GetConfig().iLlmnrLlOnly) // accept only linklocal replies to LLMNR queries
       
   594 				if (iFilter.iServerScope == EDnsServerScope_MC_LOCAL)
       
   595 					{
       
   596 					// Check compliance w. link-local addressing requirements (ipv6/ipv4)
       
   597 					if (scope_level != KIp6AddrScopeLinkLocal)
       
   598 						return KErrNotFound;
       
   599 					}
       
   600 #endif
       
   601 
       
   602 			//
       
   603 			// A backward compatibility hack: if address is IPv4 global address
       
   604 			// and the network scope in the query matches the scope of the address,
       
   605 			// then convert the returned address into old KAfInet format (and lose
       
   606 			// lose the scope id).
       
   607 			if (addr->IsV4Mapped() &&
       
   608 				addr->Scope() == aReply().iId &&
       
   609 				scope_level == KIp6AddrScopeNetwork)
       
   610 				addr->SetAddress(addr->Address());
       
   611 			}
       
   612 		}
       
   613 	return KErrNone;
       
   614 	}
       
   615 
       
   616 // TDndReqData::DoError
       
   617 // **********************
       
   618 /**
       
   619 // If a session has a DNS reply in cache associated with it, then
       
   620 // set the state of this reply to indicated error code.
       
   621 //
       
   622 // @param aError	the error code to be stored
       
   623 // @param aTLL		the new "Time To Live" for the record (in seconds). The
       
   624 //					record (and error state) will expire after this time.
       
   625 */
       
   626 void TDndReqData::DoError(TInt aError, TUint aTTL)
       
   627 	{
       
   628 	if (aError >= 0)
       
   629 		return;		// Only errors can be set!
       
   630 
       
   631 	if (iRecord == NULL)
       
   632 		return;
       
   633 	iRecord->FillErrorCode(aError, aTTL);
       
   634 	}
       
   635 
       
   636 // TDndReqData::DoQueryL
       
   637 // ***********************
       
   638 /**
       
   639 // Activate a query of specified type for the loaded query information
       
   640 // (enable RecvReply callback). Note: the callback may occur already within call!
       
   641 //
       
   642 // @param	aRequestTime is the time when the request is received from the application
       
   643 // @param	aQType	type of the query (all queries assume IN class)
       
   644 // @returns
       
   645 //	@li	< 0, serious error, (resolving process should be aborted)
       
   646 //	@li	= 0, reply found from cache (reply callback has been called)
       
   647 //	@li	= 1, DNS Query message has been queued for transmission
       
   648 // @execption
       
   649 //	LEAVE on any serious error (resolving process should be aborted)
       
   650 */
       
   651 TInt TDndReqData::DoQueryL(const TTime &aRequestTime, const EDnsQType aQType)
       
   652 	{
       
   653 	// -- class is now always IN,
       
   654 	// -- should only look from cache if aQType is not a "wildcard" type
       
   655 	//    (however, if wildcard, cache should not give hits...)
       
   656 	iQuestion.SetQType(aQType);
       
   657 	// -- only IN class queries are supported
       
   658 	iQuestion.SetQClass(EDnsQClass_IN);
       
   659 
       
   660 	if (iRecord)
       
   661 		{
       
   662 		iRecord->Unlock(this);
       
   663 		iRecord = NULL;
       
   664 		}
       
   665 
       
   666 	if (iCurrentServer == 0)
       
   667 		{
       
   668 		if (!PickDefaultServer())
       
   669 			{
       
   670 			SendResponse(KErrDndServerUnusable);
       
   671 			return 0;
       
   672 			}
       
   673 		if (iCurrentServer == 0)
       
   674 			{
       
   675 			// Cannot check cache nor start any query, if the
       
   676 			// name space id cannot be determined (no interfaces
       
   677 			// up). Return "query queued" anyway, and let the
       
   678 			// resolver retry process try it again later.
       
   679 			iIsReqPending = TRUE;
       
   680 			return 1;
       
   681 			}
       
   682 		}
       
   683 	TUint32 id = iOwner->iServerManager.NameSpace(iFilter, iCurrentServer);
       
   684 
       
   685 	if (id == 0)
       
   686 		{
       
   687 		SendResponse(KErrDndServerUnusable);
       
   688 		return 0;
       
   689 		}
       
   690 				
       
   691 	// Check in the cache first. If the record does not exist
       
   692 	// in the cache, it will be created now (empty with KErrNotFound).
       
   693 	iRecord = iOwner->iCache->FindL(
       
   694 			id,
       
   695 			iQuestion,
       
   696 			iQuestion.QType(),
       
   697 			// *HACK WARNING* To achieve independent caching of answers which
       
   698 			// are result of queries where RD=1 or RD=0 (recursion desired),
       
   699 			// the Class value is made different depending on the RD state.
       
   700 			(EDnsQClass)(iQuestion.QClass() | ((iFlags & KDnsModifier_RD) ? 0 : 0x80)),
       
   701 			aRequestTime);
       
   702 	// The above FindL must either leave of return a valid
       
   703 	// record pointer. Just as a safety measure, if record
       
   704 	// is not returned, then panic on in DEBUG builds, and
       
   705 	// in release, leave with KErrDndNoRecord
       
   706 	// (** however, this should never happen! **)
       
   707 	ASSERT(iRecord != NULL);
       
   708 	if (iRecord == NULL)
       
   709 		User::Leave(KErrDndNoRecord);
       
   710 
       
   711 	// Prevent record from being deleted while the
       
   712 	// iRecord pointer exists...
       
   713 	iRecord->Lock();
       
   714 	switch(iRecord->ErrorCode())
       
   715 		{
       
   716 		// If no error in the record, retrieve the informations and send
       
   717 		case KErrNone:	
       
   718 		// For certain errors, send the error code
       
   719 		case KErrDndBadName:
       
   720 		case KErrDndNotImplemented:
       
   721 		case KErrDndRefused:
       
   722 		case KErrDndNoRecord:
       
   723 			iIsFromCache = TRUE;
       
   724 			iIsNewQuery = FALSE;
       
   725 			if (IsQueued())
       
   726 				Cancel();
       
   727 			SendResponse(iRecord->ErrorCode());
       
   728 			return 0;
       
   729 		
       
   730 		// For other errors, try sending the query to the DNS
       
   731 		default:
       
   732 			break;
       
   733 		}
       
   734 
       
   735 	// Automatic restart of DNS socket, if closed for some reason
       
   736 	iOwner->ActivateSocketL(iNetworkId);  // pass on the networkId information
       
   737 
       
   738 	iIsReqPending = TRUE;
       
   739 	// If the query is probe, do not AssignWork but continue..
       
   740 	if (!(iFlags & KDnsModifier_PQ) && !iRecord->AssignWork(this))
       
   741 		return 1;	// just let the other worker do the job.
       
   742 
       
   743 	// Try to detect retransmissions of the same query and
       
   744 	// reuse old ID in such case... (don't generate a new)
       
   745 	if (iIsNewQuery ||
       
   746 		iQuestion.QType() != aQType ||
       
   747 		iQuestion.QClass() != EDnsQClass_IN)
       
   748 		Cancel();				// A new ID required
       
   749 
       
   750 	iIsNewQuery = FALSE;
       
   751 	iIsFromCache = FALSE;
       
   752 
       
   753 	// If the DNS "mode" is Multicast DNS, then assume that PTR queries
       
   754 	// which are generated from IP address are to be made via TCP. Test
       
   755 	// this and use TCP if query is PTR query for valid IP address.
       
   756 	// [specified in draft-ietf-dnsext-mdns-22.txt, but generalized here
       
   757 	// also for any future Multicast DNS]
       
   758 	for ( ;iFilter.IsMulticast() && iQuestion.QType() == EDnsQType_PTR;)
       
   759 		{
       
   760 		// Use "for" just for easy "break" exits!
       
   761 		TInetAddr server;
       
   762 
       
   763 		// Get correct DNS port number into 'server' (actual address is thrown away)
       
   764 		if (iOwner->iServerManager.Address(iCurrentServer, server) != KErrNone)
       
   765 			break;
       
   766 		// Use server address type as a flag, whether Ipv4 or IPv6 is done
       
   767 		const TInt is_ipv4 = server.IsV4Mapped();
       
   768 
       
   769 		if (!iQuestion.GetAddress(server) || !server.IsUnicast())
       
   770 			break;
       
   771 		// Usually LLMNR has both IPv4 and IPv6 multicast addresses as "servers".
       
   772 		// There is no point in doing PTR query for the same address twice, thus
       
   773 		// only do it once per matching "server" address (thus, if there is no
       
   774 		// IPv4 multicast "server", no IPv4 reverse queries are done either).
       
   775 		if (is_ipv4 != server.IsV4Mapped())
       
   776 			{
       
   777 			SendResponse(KErrDndServerUnusable);
       
   778 			return 0;
       
   779 			}
       
   780 
       
   781 		// Supplement 'server' address with a scope id based on current server
       
   782 		server.SetScope(iOwner->iServerManager.Scope(iCurrentServer, server));
       
   783 
       
   784 		// For link local multicast, use TTL = 1 (otherwise, system default is used)
       
   785 		const TInt ttl = iFilter.iServerScope == EDnsServerScope_MC_LOCAL ? 1 : -1;
       
   786 		if (iOwner->Queue(*this, server, -1, ttl) != KErrNone)
       
   787 			break;
       
   788 		iIsUsingTCP = 1;
       
   789 		SendResponse(KDnsNotify_USING_TCP);
       
   790 		return 1;
       
   791 		}
       
   792 	iOwner->ReSend(*this);		// (uses old ID, if request queued already)
       
   793 	return 1;
       
   794 	}
       
   795 
       
   796 // TDndReqData::UpdateCacheData
       
   797 // ******************************
       
   798 /**
       
   799 // @param aQuery	the session from which the reply is updated
       
   800 // @param aMsg		the reply from the DNS server
       
   801 // @param aAnswerOffset the start offset to the andwer secion in the reply
       
   802 // @param aErr		the status code of the reply
       
   803 // @returns
       
   804 //	@li	TRUE, if cache record updated
       
   805 //	@li	FALSE, if not updated (error code is "transient", concerns single query)
       
   806 */
       
   807 TBool TDndReqData::UpdateCacheData(const TMsgBuf &aMsg, const TInt aAnswerOffset, const TInt aErr)
       
   808 	{
       
   809 	if (iRecord == NULL)
       
   810 		return FALSE;
       
   811 
       
   812 #ifdef _LOG
       
   813 	THostName name;
       
   814 	iQuestion.GetName(name);
       
   815 	Log::Printf(_L("\t\tDNS session [%u] -- Update cache: %S (offset=%d) aErr=%d"), (TInt)this, &name, aAnswerOffset, aErr);
       
   816 #endif
       
   817 	if (aErr == KErrDndDiscard)
       
   818 		return FALSE;
       
   819 
       
   820 	// If there is already have valid answer cached, decide whether the new
       
   821 	// answer is better and should replace the old?
       
   822 	const TInet6HeaderDNS &new_hdr = aMsg.Header();
       
   823 	if (iRecord->ErrorCode() == KErrNone && !new_hdr.AA())
       
   824 		{
       
   825 		// If new header is not authoritative, then it will replace the value
       
   826 		// only if old is non-authoritative and there is no error.
       
   827 		const TInet6HeaderDNS &old_hdr = iRecord->Header();
       
   828 		if (old_hdr.AA() || aErr != KErrNone)
       
   829 			return FALSE; // Not updated, keep previous valid value in cache.
       
   830 		}
       
   831 
       
   832 	TBool updated = FALSE;
       
   833 	if (aErr == KErrNone || aErr == KErrDndBadName || aErr == KErrDndNotImplemented || aErr == KErrDndNoRecord)
       
   834 		{
       
   835 		// Try to locate the SOA record from the authority section and
       
   836 		// use the minttl as the ttl of the negative caching.
       
   837 		TInt ttl;
       
   838 		TDndRR soa(aMsg);
       
   839 #ifdef SYMBIAN_DNS_PUNYCODE
       
   840 		soa.iIdnEnabled = (TBool) iIdnEnabled;
       
   841 #endif //SYMBIAN_DNS_PUNYCODE
       
   842 		TInt off = soa.LocateRR(aAnswerOffset, new_hdr.ANCOUNT()+new_hdr.NSCOUNT(), EDnsQType_SOA, EDnsQClass_IN, new_hdr.ANCOUNT());
       
   843 		if (off < 0)
       
   844 			{
       
   845 			ttl = iOwner->iControl.GetConfig().iMaxTime;
       
   846 			LOG(Log::Printf(_L("\t\tDNS session [%u] -- Update cache: no SOA, default ttl = %d"), (TInt)this, ttl));
       
   847 			}
       
   848 		else if ((off = aMsg.SkipName(soa.iRd)) > 0 &&
       
   849 				 (off = aMsg.SkipName(off)) > 0 &&
       
   850 				 off >= (TInt)soa.iRd &&
       
   851 				 off + 20 <= (TInt)(soa.iRd + soa.iRdLength))
       
   852 			{
       
   853 			ttl = BigEndian::Get32(aMsg.Ptr()+off+16);
       
   854 			LOG(Log::Printf(_L("\t\tDNS session [%u] -- Update cache: SOA minttl = %d"), (TInt)this, ttl));
       
   855 			}
       
   856 		else
       
   857 			{
       
   858 			ttl = 0;	// The reply is broken in some way, use ttl = 0
       
   859 			LOG(Log::Printf(_L("\t\tDNS session [%u] -- Update cache: SOA access failed"), (TInt)this));
       
   860 			}
       
   861 		iRecord->FillData(aMsg, aAnswerOffset, iCurrentServer, aErr, ttl);
       
   862 #ifdef SYMBIAN_DNS_PUNYCODE
       
   863 		
       
   864 		LOG(iRecord->Print(iOwner->iControl,(TBool)iIdnEnabled));
       
   865 #else
       
   866 		LOG(iRecord->Print(iOwner->iControl));
       
   867 #endif //SYMBIAN_DNS_PUNYCODE
       
   868 		updated = TRUE;
       
   869 		}
       
   870 	//
       
   871 	// Got some answer from a server, update the "good" server (unless error indicates "bad"
       
   872 	//
       
   873 	if (iFilter.IsUnicast() && aErr != KErrDndRefused && aErr != KErrDndServerUnusable)
       
   874 		{
       
   875 		TInetAddr addr;
       
   876 		if (iOwner->iServerManager.Address(iCurrentServer, addr) == KErrNone)
       
   877 			{
       
   878 #ifdef _LOG
       
   879 			// borrow the 'name' from earlier LOG section!
       
   880 			addr.OutputWithScope(name);
       
   881 			Log::Printf(_L("\t\tDNS session [%u] -- Update cache: preferred server = %S port=%d ns=%d"),
       
   882 				(TInt)this, &name, addr.Port(), iOwner->iServerManager.NameSpace(iFilter, iCurrentServer));
       
   883 #endif
       
   884 			iOwner->iCache->SetServerAddress(iOwner->iServerManager.NameSpace(iFilter, iCurrentServer), addr, KErrNone);
       
   885 			}
       
   886 		}
       
   887 
       
   888 	return updated;
       
   889 	}
       
   890 
       
   891 
       
   892 void CDndDnsclient::QueryBegin()
       
   893 	{
       
   894 	++iActivityCount;
       
   895 	}
       
   896 
       
   897 
       
   898 void CDndDnsclient::QueryEnd()
       
   899 	{
       
   900 	ASSERT(iActivityCount > 0);
       
   901 	if (--iActivityCount == 0)
       
   902 		DeactivateSocket();
       
   903 	}
       
   904 
       
   905 
       
   906 //
       
   907 // TDndReqData
       
   908 //
       
   909 
       
   910 // TDndReqData::TranslateRCODE
       
   911 // ***************************
       
   912 /**
       
   913 //
       
   914 // @param	aHdr	The fixed DNS reply header
       
   915 //
       
   916 // @returns
       
   917 //	@li	KErrNone, if reply is ok
       
   918 //	@li	KErrDndDiscard/KErrDndUnknown
       
   919 //		if reply does not match the query, has errors
       
   920 //		in the format or RCODE was unknown
       
   921 //	@li	KErrDndFormat, RCODE was EDnsRcode_FORMAT_ERROR
       
   922 //	@li	KErrDndServerFailure, RCODE was EDnsRcode_SERVER_FAILURE
       
   923 //	@li	KErrDndBadName, RCODE was EDnsRcode_NAME_ERROR
       
   924 //	@li	KErrDndNotImplemented, RCODE was EDnsRcode_NOT_IMPLEMENTED
       
   925 //	@li	KErrDndRefuced, RCODE was EDnsRcode_REFUSED
       
   926 //	@li	KErrDndServerUnusable, if empty reply is not authoritative
       
   927 */
       
   928 TInt TDndReqData::TranslateRCODE(const TDndHeader &aHdr, TInt aRCode) const
       
   929 	{
       
   930 	switch (aRCode) 
       
   931 		{
       
   932 		case EDnsRcode_NOERROR:
       
   933 			break;
       
   934 		case EDnsRcode_FORMAT_ERROR:
       
   935 			return KErrDndFormat;
       
   936 		case EDnsRcode_SERVER_FAILURE:
       
   937 			return KErrDndServerFailure;
       
   938 		case EDnsRcode_NAME_ERROR:
       
   939 			return KErrDndBadName;
       
   940 		case EDnsRcode_NOT_IMPLEMENTED:
       
   941 			return KErrDndNotImplemented;
       
   942 		case EDnsRcode_REFUSED:
       
   943 			return KErrDndRefused;
       
   944 		default:
       
   945 			return KErrDndUnknown;
       
   946 		}	
       
   947 
       
   948 	if (iOpcode == EDnsOpcode_QUERY && aHdr.QDCOUNT() != iQdCount)
       
   949 		return KErrDndDiscard;
       
   950 	//
       
   951 	// A special heuristics: discard empty replies, if the selected server does
       
   952 	// not do recursion as requested, and if it is not authority on the queried
       
   953 	// name. => return a special "server unusable for this query" error
       
   954 	if (aHdr.ANCOUNT() == 0 && (iFlags & KDnsModifier_RD) != 0 && !aHdr.RA() && !aHdr.AA())
       
   955 		return KErrDndServerUnusable;
       
   956 	return KErrNone;
       
   957 	}
       
   958 
       
   959 // TDndReqData::CheckQuestion
       
   960 // **************************
       
   961 /**
       
   962 // @param	aOffset starting offset of the question section in the message
       
   963 // @param	aMsg the reply message from a DNS server
       
   964 //
       
   965 // @returns
       
   966 //	@li	> 0,
       
   967 //		if message checks ok, the value is the new offset pointing
       
   968 //		to the next section after the question.
       
   969 //	@li	= 0, reply does not match the question.
       
   970 //	@li < 0, bad DNS reply
       
   971 */
       
   972 TInt TDndReqData::CheckQuestion(const TMsgBuf &aMsg, TInt &aRCode) const
       
   973 	{
       
   974 	if (!iIsReqPending)
       
   975 		return 0;	// Not for me.
       
   976 
       
   977 	TDndQuestion question;
       
   978 	const TInt offset = aMsg.VerifyMessage(aRCode, question);
       
   979 	if (offset < 0)
       
   980 		return offset;	// Invalid message format, just ignore.
       
   981 	const TDndHeader &hdr = aMsg.Header();
       
   982 
       
   983 	// Only ONE question supported, sematics of receiving a reply
       
   984 	// with more than one Question are hairy... [which answers
       
   985 	// relate to which question?] (and multiple questions are
       
   986 	// not supported by current servers anyway -- msa)
       
   987 	if (hdr.QDCOUNT() != 1)
       
   988 		return KErrDndUnknown;
       
   989 
       
   990 	// This is supposed to be a REPLY, if not, then "no match".
       
   991 	if (!hdr.QR())
       
   992 		return 0;
       
   993 	// Reply OPCODE match the query?
       
   994 	if (hdr.OPCODE() != iOpcode)
       
   995 		return KErrDndDiscard;
       
   996 
       
   997 	// Does the question match the query?
       
   998 	//
       
   999 	if (question.CheckQuestion(iQuestion) != KErrNone)
       
  1000 		return 0;
       
  1001 	return offset;
       
  1002 	}
       
  1003 
       
  1004 
       
  1005 // TDndReqData::GetResponse
       
  1006 // ************************
       
  1007 /**
       
  1008 // Map the contents of single resource record into TNameRecord.
       
  1009 //
       
  1010 // @param	aRR	the resource from which the reply is extracted
       
  1011 // @retval	aAnswer receives the extracted value
       
  1012 // @returns
       
  1013 //	@li	KErrNone, if extraction successful
       
  1014 //	@li	KErrDndNameTooBig, if answer cannot be fit into aAnswer
       
  1015 //	@li and other errors
       
  1016 */
       
  1017 TInt TDndReqData::GetResponse(const TDndRR &aRR, TNameRecord &aAnswer) const
       
  1018 	{
       
  1019 	TInt err = aRR.GetResponse(aAnswer.iName, TInetAddr::Cast(aAnswer.iAddr));
       
  1020 	if (err != KErrNone)
       
  1021 		return err;
       
  1022 	aAnswer.iFlags |= (aRR.iType == EDnsType_CNAME) ? (EDnsAlias | EDnsServer) : EDnsServer;
       
  1023 	return KErrNone;
       
  1024 	}
       
  1025 
       
  1026 
       
  1027 // TDndReqData::SendResponce
       
  1028 // *************************
       
  1029 /**
       
  1030 // @param	aErr is the status,
       
  1031 //	@li	= 0, the request has completed successfully
       
  1032 //	@li > 0, request being processed, just a progress noticification
       
  1033 //	@li	< 0, the request has completed with an error
       
  1034 */
       
  1035 void TDndReqData::SendResponse(TInt aErr)
       
  1036 	{
       
  1037 	if (aErr <= 0)
       
  1038 		{
       
  1039 		iIsReqPending = FALSE;	// Current request completed
       
  1040 		Cancel();
       
  1041 		}
       
  1042 	if (iCallback)
       
  1043 		iCallback->ReplyCallback(aErr);
       
  1044 	}
       
  1045 
       
  1046 // TDndReqData::Build
       
  1047 // ******************
       
  1048 /**
       
  1049 // @retval	aMsg
       
  1050 //		contains the fully constructed message to be sent to the DNS server,
       
  1051 //		if Build succeeds
       
  1052 // @retval	aServer
       
  1053 //		contains the server address for which the message should be sent
       
  1054 // @param	aMaxMessage
       
  1055 //		the size of the current receive buffer (if UDP, zero for TCP)
       
  1056 //
       
  1057 // @returns TRUE, successful Build, and error (< 0) otherwise
       
  1058 */
       
  1059 TBool TDndReqData::Build(CDnsSocket &aSource, TMsgBuf &aMsg, TInetAddr &aServer, TInt aMaxMessage)
       
  1060 	{
       
  1061 	CDndDnsclient &dns = (CDndDnsclient &)aSource;
       
  1062 
       
  1063 	if (dns.iServerManager.Address(iCurrentServer, aServer) != KErrNone)
       
  1064 		return 0;
       
  1065 	ASSERT(aServer.Port() != 0);
       
  1066 
       
  1067 	aMsg.SetLength(sizeof(TDndHeader));
       
  1068 	TDndHeader &hdr = (TDndHeader &)aMsg.Header();
       
  1069 	if (aServer.IsMulticast())
       
  1070 		{
       
  1071 		ASSERT(iFilter.IsMulticast());
       
  1072 		hdr.SetRD(0);
       
  1073 		if (aServer.IsV4Mapped())
       
  1074 			{
       
  1075 			if(iQuestion.QType() == EDnsQType_AAAA)
       
  1076 				{
       
  1077 				SendResponse(KErrDndServerUnusable);
       
  1078 				return 0;
       
  1079 				}
       
  1080 			}
       
  1081 		else
       
  1082 			{
       
  1083 
       
  1084 			if(iQuestion.QType() == EDnsQType_A)
       
  1085 				{
       
  1086 				SendResponse(KErrDndServerUnusable);
       
  1087 				return 0;
       
  1088 				}
       
  1089 			}
       
  1090 #ifdef LLMNR_ENABLED
       
  1091 		dns.SetHoplimit(dns.iControl.GetConfig().iLlmnrHoplimit);
       
  1092 #endif
       
  1093 		}
       
  1094 	else
       
  1095 		{
       
  1096 #ifdef LLMNR_ENABLED
       
  1097 		dns.SetHoplimit(-1);
       
  1098 #endif
       
  1099 		hdr.SetRD(iFlags & KDnsModifier_RD);
       
  1100 		}
       
  1101 	hdr.SetQdCount(1);
       
  1102 	if (iQuestion.Append(aMsg) < 0)
       
  1103 		return 0;
       
  1104 
       
  1105 	// Assume EDNS0 enabled, if the current receive buffer
       
  1106 	// is larger than KDnsMaxMessage (all smaller
       
  1107 	// values are treated as "no EDNS0".
       
  1108 	if (aMaxMessage > KDnsMaxMessage)
       
  1109 		{
       
  1110 		TDndRROut opt(aMsg);
       
  1111 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1112 		opt.iIdnEnabled = (TBool) iIdnEnabled;
       
  1113 #endif //SYMBIAN_DNS_PUNYCODE
       
  1114 		opt.iType = (TUint16)EDnsQType_OPT;
       
  1115 		opt.iClass = (TUint16)aMaxMessage;
       
  1116 		opt.iTTL = 0;	// RCODE = 0, version = 0, Z = 0
       
  1117 		if (opt.Append(KNullDesC8, 0) == KErrNone)
       
  1118 			{
       
  1119 			hdr.SetArCount(1);
       
  1120 			opt.AppendRData();
       
  1121 			}
       
  1122 		}
       
  1123 	return 1;
       
  1124 	}
       
  1125 
       
  1126 
       
  1127 void TDndReqData::Sent(CDnsSocket &aSource)
       
  1128 	{
       
  1129 	CDndDnsclient &dns = (CDndDnsclient &)aSource;
       
  1130 
       
  1131 	dns.iServerManager.CloseList(iFilter);
       
  1132 
       
  1133 	SendResponse(KDnsNotify_QUERY_SENT);
       
  1134 	}
       
  1135 
       
  1136 
       
  1137 TBool TDndReqData::Reply(CDnsSocket &aSource, const TMsgBuf &aBuf, const TInetAddr &aServer)
       
  1138 	{
       
  1139 	TInt rcode = 0;
       
  1140 	const TInt offset = CheckQuestion(aBuf, rcode);
       
  1141 	if (offset < 0)
       
  1142 		return 1;	// Invalid message format, just ignore.
       
  1143 	const TDndHeader &hdr = aBuf.Header();
       
  1144 	TInt err = TranslateRCODE(hdr, rcode);
       
  1145 
       
  1146 	CDndDnsclient &dns = (CDndDnsclient &)aSource;
       
  1147 	ASSERT(&dns == iOwner);
       
  1148 	// If configuration requests that "Not found" replies from a server
       
  1149 	// are not to be cached, but ignored, then substitue err with
       
  1150 	// KErrDndServerUnusable (meaning that this server is not usable for
       
  1151 	// this query) This error is not cached!
       
  1152 	//
       
  1153 	if (err == KErrDndBadName && dns.iControl.GetConfig().iSkipNotFound)
       
  1154 		err = KErrDndServerUnusable;
       
  1155 	else if (iIsUsingTCP == 0 && hdr.TC() != 0)
       
  1156 		{
       
  1157 		// The current query was not TCP and got truncated reply,
       
  1158 		// restart query with TCP (if we get truncated reply with
       
  1159 		// TCP, something is broken...)
       
  1160 		//
       
  1161 
       
  1162 		// It is assumed that the aServer has the correct port
       
  1163 		// already set (it should be the remote port of the original
       
  1164 		// UDP query)
       
  1165 		ASSERT(aServer.IsUnicast());	// Should always be true.
       
  1166 		if (aServer.IsUnicast())
       
  1167 			{
       
  1168 			if (iOwner->Queue(*this, aServer, hdr.ID()) == KErrNone)
       
  1169 				{
       
  1170 				iIsUsingTCP = 1;
       
  1171 				SendResponse(KDnsNotify_USING_TCP);
       
  1172 				return 1;
       
  1173 				}
       
  1174 			}
       
  1175 		// If cannot use the TCP, then just use the trunctated
       
  1176 		// answer as is...
       
  1177 		}
       
  1178 	//
       
  1179 	// UpdateCacheData updates data in cache only, if err is KErrNone, or
       
  1180 	// updates error status for some specific err codes,
       
  1181 	// otherwise, it does nothing.
       
  1182 	TBool updated = UpdateCacheData(aBuf, offset, err);
       
  1183 
       
  1184 #ifdef DEBUG_CACHE
       
  1185 	iCache->Dump(*iControl);
       
  1186 #endif
       
  1187 
       
  1188 	if (updated)
       
  1189 		{
       
  1190 		// Cache modified! In addition to the original query,
       
  1191 		// send the responce to every request that is waiting for
       
  1192 		// the same reply... (iRecord pointers are same).
       
  1193 		for (TUint i = 0; i < KDndNumRequests; ++i)
       
  1194 			{
       
  1195 			TDndReqData &rq = dns.iDndReqData[i];
       
  1196 			if (rq.iIsReqPending && iRecord == rq.iRecord)
       
  1197 				{
       
  1198 				rq.Cancel();	// No need to send the query
       
  1199 				rq.SendResponse(err);
       
  1200 				}
       
  1201 			}
       
  1202 		return 1;
       
  1203 		}
       
  1204 
       
  1205 	// Cache not updated, send to original query only.
       
  1206 	SendResponse(err);
       
  1207 	return 1;
       
  1208 	}
       
  1209 
       
  1210 void TDndReqData::Abort(CDnsSocket &/*aSource*/, const TInt aReason)
       
  1211 	{
       
  1212 	SendResponse(aReason);
       
  1213 	}