tcpiputils/dnd/src/llmnrresponder.cpp
changeset 0 af10295192d8
child 75 c1029e558ef5
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 // llmnrresponder.cpp - DND Link-local Multicast Name Resolution 
       
    15 // responder module 
       
    16 //
       
    17 
       
    18 #ifdef LLMNR_ENABLED
       
    19 #include <e32math.h>
       
    20 #include <in_iface.h>
       
    21 #include <in6_if.h>
       
    22 #include "engine.h"
       
    23 #include "llmnrresponder.h"
       
    24 #include "llmnrconflict.h"
       
    25 #include <networking/dnd_err.h>
       
    26 #include "serverconf.h"
       
    27 #include "inet6log.h"
       
    28 
       
    29 
       
    30 enum TEntryState
       
    31 	{
       
    32 	EInactive = 0,	//< Entry is not yet available
       
    33 	EUnique = 1,	//< Entry is unique and alive
       
    34 	EDisabled = -1,	//< Entry is faulty, disabled
       
    35 	EConflict = -2	//< Entry has conflict with another host
       
    36 	};
       
    37 
       
    38 class CNotifyConflict : public CActive
       
    39 	/**
       
    40 	Exists while a conflict notifier process is active.
       
    41 	*/
       
    42 	{
       
    43 private:
       
    44 	CNotifyConflict(CDndLlmnrResponder &aResponder, CLlmnrEntry &aEntry);
       
    45 	void DoStart();
       
    46 public:
       
    47 	~CNotifyConflict();
       
    48 	static void Start(CDndLlmnrResponder &aResponder, CLlmnrEntry &aEntry);
       
    49 
       
    50 	void DoCancel();
       
    51 	void RunL();
       
    52 
       
    53 	CDndLlmnrResponder &iResponder;
       
    54 	CLlmnrEntry &iEntry;
       
    55 	TPckgBuf<TLlmnrConflictNotify> iInfo;
       
    56 	RNotifier iNotifier;
       
    57 	TUint iConnected:1;
       
    58 	};
       
    59 
       
    60 class CLlmnrEntry : public CBase
       
    61 	/**
       
    62 	Describes an answer (RR) that can be asked from this node.
       
    63 
       
    64 	An instance of this object is created for each unique answer
       
    65 	which this node is responsible for at this point of time.
       
    66 	Each entry describes an answer for a specific interface.
       
    67 	If the same name is defined for multiple interfaces,
       
    68 	then multiple instances are created
       
    69 	(one for each interface).
       
    70 	
       
    71 	These entries are created and deleted dynamically, as
       
    72 	interfaces go up and down.
       
    73 	*/
       
    74 	{
       
    75 public:
       
    76 	~CLlmnrEntry();
       
    77 
       
    78 	CLlmnrEntry *iNext;				//< Links the entry set together (head is CDndLlmnrResponder::iEntryList)
       
    79 	TDndQuestion iQuestion;			//< The question that is answered by this entry
       
    80 	TInetScopeIds iZone;			//< The scope vector of the related interface.
       
    81 	TIpVer iVersion:8;				//< Which protocol: IPv4 or IPv6
       
    82 	TEntryState iState:8;			//< State of this entry.
       
    83 	TUint iDown:1;					//< Used in interface tracking
       
    84 	TUint iHostName:1;				//< Set 1, if the name depends on the local hostname.
       
    85 	CNotifyConflict *iNotify;		//< Non-NULL when conlict nofitication is in progress
       
    86 	};
       
    87 
       
    88 
       
    89 
       
    90 // TRawAddr
       
    91 // *********
       
    92 // Lightweight internal help class for handling the link layer addresses
       
    93 // (modified from ipadm engine.cpp)
       
    94 class TRawAddr : public TSockAddr
       
    95 	{
       
    96 public:
       
    97 
       
    98 	TInt Append(TDes8& aBuf) const
       
    99 		{
       
   100 		TUint8* p = (TUint8*)UserPtr();
       
   101 		TInt len = ((TSockAddr *)this)->GetUserLen();
       
   102 
       
   103 		if (len == 0)
       
   104 			return KErrNotSupported;
       
   105 		if (aBuf.MaxLength() < aBuf.Length() + len * 2)
       
   106 			return KErrNoMemory;
       
   107 
       
   108 		while (--len >= 0)
       
   109 			aBuf.AppendFormat(_L8("%02X"), *p++ & 0xFF);
       
   110 
       
   111 		return KErrNone;
       
   112 		}
       
   113 
       
   114 	inline static TRawAddr& Cast(const TSockAddr& aAddr)
       
   115 		{
       
   116 		return *((TRawAddr *)&aAddr);
       
   117 		}
       
   118 	};
       
   119 	
       
   120 
       
   121 CLlmnrEntry::~CLlmnrEntry()
       
   122 	{
       
   123 	delete iNotify;
       
   124 	}
       
   125 
       
   126 
       
   127 CDndLlmnrResponder::CDndLlmnrResponder(CDndEngine &aControl,
       
   128 									   MDnsServerManager &aServerManager,
       
   129 									   THostNames &aHostNames)
       
   130 	: iControl(aControl),
       
   131 	  iServerManager(aServerManager),
       
   132 	  iHostNames(aHostNames)
       
   133 	{
       
   134 
       
   135 	// Need to initialize the request blocks with "parent" pointer
       
   136 	for (TUint i = 0; i < sizeof(iLlmnrDataList) / sizeof(iLlmnrDataList[0]); ++i)
       
   137 		iLlmnrDataList[i].iParent = this;
       
   138 	}
       
   139 
       
   140 CDndLlmnrResponder::~CDndLlmnrResponder()
       
   141 	{
       
   142 	// Make sure all requests are totally idle
       
   143 	for (TUint i = 0; i < sizeof(iLlmnrDataList) / sizeof(iLlmnrDataList[0]); ++i)
       
   144 		{
       
   145 		iLlmnrDataList[i].iTimeout.Cancel();
       
   146 		iLlmnrDataList[i].Cancel();
       
   147 		}
       
   148 	while (iEntryList)
       
   149 		{
       
   150 		CLlmnrEntry *p = iEntryList;
       
   151 		iEntryList = p->iNext;
       
   152 		delete p;
       
   153 		}
       
   154 	delete iLlmnrNotifyHandler;
       
   155 	delete iLlmnrConf;
       
   156 	}
       
   157 
       
   158 void CDndLlmnrResponder::ConstructL()
       
   159 	{
       
   160 	LOG(Log::Printf(_L("CDndLlmnrResponder::ConstructL() size=%d\r\n"), (TInt)sizeof(*this)));
       
   161 	CDnsSocket::ConstructL ();
       
   162 	iLlmnrConf = new (ELeave) CLlmnrConf(iControl);
       
   163 	iLlmnrConf->ConstructL();
       
   164 	iLlmnrConf->GetHostNamesL();
       
   165 
       
   166 	iLlmnrNotifyHandler = new (ELeave) CDndLlmnrNotifyHandler(*this);
       
   167 	iLlmnrNotifyHandler->ConstructL();
       
   168 	}
       
   169 	
       
   170 void CDndLlmnrResponder::ConfigurationChanged()
       
   171 	{
       
   172 	iLlmnrNotifyHandler->ConfigurationChanged();
       
   173 	}
       
   174 
       
   175 void CDndLlmnrResponder::ActivateSocketL()
       
   176 	{
       
   177 	if (iConnected && IsOpened())
       
   178 		return;			// Assume all done
       
   179 
       
   180 	const TDndConfigParameters &cf = iControl.GetConfig();
       
   181 	const TInetAddr bind(TInetAddr(cf.iLlmnrPort));
       
   182 
       
   183 	CDnsSocket::ActivateSocketL(bind);
       
   184 
       
   185 	// Disable multicast loopback to lessen the possibility to receive our own replies
       
   186 	(void)Socket().SetOpt(KSoIp6MulticastLoop, KSolInetIp, 0);
       
   187 	// Set Unicast and Multicast TTL/Hop limit to 1 for LLMNR responses
       
   188 	(void)Socket().SetOpt(KSoIp6UnicastHops, KSolInetIp, cf.iLlmnrHoplimit);
       
   189 	(void)Socket().SetOpt(KSoIp6MulticastHops, KSolInetIp, cf.iLlmnrHoplimit);
       
   190 	(void)Socket().SetOpt(KSoUserSocket, KSolInetIp, 0);
       
   191 	// THe LLMNR responder socket does not need to keep the interfaces up.
       
   192 	(void)Socket().SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0);
       
   193 	ActivateListenL(bind, 1);
       
   194 	}
       
   195 
       
   196 // Join multicast group to LLMNR responder iSocket
       
   197 TInt CDndLlmnrResponder::JoinMulticastGroup(TUint32 aIndex, TIpVer aIpVer)
       
   198 	{
       
   199 
       
   200 	TPckgBuf<TIp6Mreq> opt;
       
   201 
       
   202 	TRAPD(err, ActivateSocketL());	// Need socket opened...
       
   203 	if (err != KErrNone)
       
   204 		return err;
       
   205 
       
   206 	if(aIpVer == EIPv4)
       
   207 		opt().iAddr = iControl.GetConfig().iLlmnrIpv4;
       
   208 	else
       
   209 		opt().iAddr = iControl.GetConfig().iLlmnrIpv6;
       
   210 	opt().iInterface = aIndex;
       
   211 
       
   212 	err=Socket().SetOpt(KSoIp6JoinGroup, KSolInetIp, opt);
       
   213 
       
   214 	if ((err != KErrNone)&&(err != KErrInUse)) // may return KErrInUse when multicast hook is on
       
   215 		{
       
   216 		LOG(Log::Printf(_L("CDndLlmnrResponder::JoinMulticastGroup SetOpt KSoIp6JoinGroup if=%d error: %d"), aIndex, err));
       
   217 		return err;
       
   218 		}
       
   219 
       
   220 	return KErrNone;
       
   221 	}
       
   222 
       
   223 
       
   224 TInt CDndLlmnrResponder::MakeMyAddr(const TUint32 aIfIndex, const TInetAddr &aTarget, EDnsType aType, TInetAddr &aAddr)
       
   225 	{
       
   226 	const EDnsType target_type = (aTarget.Family() == KAfInet || aTarget.IsV4Mapped()) ? EDnsType_A : EDnsType_AAAA;
       
   227 
       
   228 	TPckgBuf<TSoInetIfQuery> opt;
       
   229 	opt().iIndex = aIfIndex;
       
   230 
       
   231 	for (;;)
       
   232 		{
       
   233 		TInt err;
       
   234 
       
   235 		if (aType == target_type)
       
   236 			{
       
   237 			// The target address matches the address type being queried,
       
   238 			// try obtaining the "best address" that matches the target.
       
   239 			opt().iDstAddr = aTarget;
       
   240 			if ((err = iControl.iSocket.GetOpt(KSoInetIfQueryByIndex, KSolInetIfQuery, opt)) != KErrNone)
       
   241 				return err;
       
   242 			if (!opt().iSrcAddr.IsUnspecified())
       
   243 				break;	// Success!
       
   244 			}
       
   245 
       
   246 		// Try finding an acceptable link local or any higher scope address
       
   247 
       
   248 		if (aType == EDnsType_A)
       
   249 			opt().iDstAddr.SetV4MappedAddress(KInetAddrLinkLocalNet); 
       
   250 		else if (aType == EDnsType_AAAA)
       
   251 			opt().iDstAddr.SetAddress(KInet6AddrLinkLocal);
       
   252 		else
       
   253 			return KErrNotSupported;
       
   254 
       
   255 		if ((err = iControl.iSocket.GetOpt(KSoInetIfQueryByIndex, KSolInetIfQuery, opt)) != KErrNone)
       
   256 			{
       
   257 			LOG(Log::Printf(_L("CDndLlmnrResponder::MakeMyAddr GetOpt KSoInetIfQueryByIndex error: %d"),err));
       
   258 			return err;
       
   259 			}
       
   260 		break;
       
   261 		// *NEVER GET HERE!*
       
   262 		}
       
   263 	//
       
   264 	// Address is unspecified or some valid source address
       
   265 	//
       
   266 	aAddr = opt().iSrcAddr;
       
   267 	return KErrNone;
       
   268 	}
       
   269 
       
   270 
       
   271 #ifdef _LOG
       
   272 void CDndLlmnrResponder::LogPrint(const TDesC &aStr, const CLlmnrEntry &aEntry)
       
   273 	{
       
   274 	TBuf<KDnsMaxName> name;
       
   275 
       
   276 	aEntry.iQuestion.GetName(name);
       
   277 
       
   278 	Log::Printf(_L("%S%S QType=%d State=%d ip%d for if=%u\r\n"),
       
   279 		&aStr,
       
   280 		&name, (TInt)aEntry.iQuestion.QType(),
       
   281 		(TInt)aEntry.iState,
       
   282 		(TInt)aEntry.iVersion,
       
   283 		(TInt)aEntry.iZone[0]);
       
   284 	}
       
   285 
       
   286 void CDndLlmnrResponder::LogPrint(const TDesC &aStr, const TDndQuestion &aQuestion)
       
   287 	{
       
   288 	TBuf<KDnsMaxName> name;
       
   289 
       
   290 	aQuestion.GetName(name);
       
   291 
       
   292 	Log::Printf(_L("%S%S QType=%d\r\n"),
       
   293 		&aStr,
       
   294 		&name, (TInt)aQuestion.QType());
       
   295 	}
       
   296 #endif
       
   297 
       
   298 // Mark all entries as "unupdated"
       
   299 void CDndLlmnrResponder::UpdateStart()
       
   300 	{
       
   301 	for(CLlmnrEntry *entry = iEntryList; entry != NULL; entry = entry->iNext)
       
   302 		entry->iDown = 1;
       
   303 	}
       
   304 
       
   305 // Remove all entries that were not updated (interface has gone down)
       
   306 void CDndLlmnrResponder::UpdateFinish()
       
   307 	{
       
   308 	for(CLlmnrEntry **h = &iEntryList;;)
       
   309 		{
       
   310 		CLlmnrEntry *entry = *h;
       
   311 		if (entry == NULL)
       
   312 			break;	// -- all done!
       
   313 		if (entry->iDown ||
       
   314 			JoinMulticastGroup(entry->iZone[0], STATIC_CAST(TIpVer, entry->iVersion)) != KErrNone)
       
   315 			{
       
   316 			//
       
   317 			// Remove entry. Either interface is down (not exist) or
       
   318 			// it does not support multicast, in which case it cannot
       
   319 			// be used for LLMNR.
       
   320 			//
       
   321 			*h = entry->iNext;
       
   322 			//
       
   323 			// If entry has any associated requests outstanding,
       
   324 			// they must be cancelled.
       
   325 			CancelAll(*entry);
       
   326 			LOG(LogPrint(_L("\tLLMNR removed: "), *entry));
       
   327 			delete entry;
       
   328 			}
       
   329 		else
       
   330 			{
       
   331 			//
       
   332 			// Entry is still active and usable
       
   333 			//
       
   334 			h = &entry->iNext;
       
   335 			continue;
       
   336 			}
       
   337 		}
       
   338 	if (iEntryList == NULL)
       
   339 		{
       
   340 		// Nothing enabled for LLMNR, no need to keep the socket either
       
   341 		DeactivateSocket();
       
   342 		LOG(Log::Printf(_L("CDndLlmnrResponder::UpdateFinish - no entries, socket deactivated\r\n")));
       
   343 		}
       
   344 	}
       
   345 
       
   346 TInt CDndLlmnrResponder::UpdateInterface
       
   347 	(const TName &aIfName, const TIpVer aIpVer, const TInetScopeIds &aZone, const TSockAddr &aHwAddr, TInt aLlmnrDisable)
       
   348 	/**
       
   349 	* Update the LLMNR entries for the specified interface.
       
   350 	*
       
   351 	* @param aIfName	The interface name
       
   352 	* @parma aIpVer		The IP version (either EIPv4 or EIPv6)
       
   353 	* @param aZone		The zone ids
       
   354 	* @param aHwAddr	The hardware address (if present)
       
   355 	* @param aLlmnrDisable	=1, if LLMNR is to be disabled on this interface
       
   356 	*/
       
   357 	{
       
   358 
       
   359 	// Check that this is not a loopback interface
       
   360 	if(!aZone[1])
       
   361 		return KErrNone;
       
   362 
       
   363 	// An interface is open. Check if it is LLMNR enabled and if update(s)
       
   364 	// have not been sent or disabled
       
   365 
       
   366 	TInt is_active = 0;
       
   367 	for(CLlmnrEntry *entry = iEntryList; entry != NULL; entry = entry->iNext)
       
   368 		{
       
   369 		if (entry->iZone[0] == aZone[0])
       
   370 			{
       
   371 			is_active = 1;
       
   372 			// If LLMNR is to be disable, this keeps iDown as 1 and
       
   373 			// the entry will be deleted in UpdateFinish.
       
   374 			entry->iDown = aLlmnrDisable;
       
   375 			//
       
   376 			// Copy the scope vector each time, in case it has been modified
       
   377 			//
       
   378 			for (TUint k = 0; k < sizeof(TInetScopeIds) / sizeof(entry->iZone[0]); k++)
       
   379 				entry->iZone[k] = aZone[k];
       
   380 			}
       
   381 		}
       
   382 	if (is_active || aLlmnrDisable)
       
   383 		return KErrNone;	// Interface already activated or being disabled, nothing else to do.
       
   384 
       
   385 	// Interface is not yet LLMNR enabled, Check if there
       
   386 	// are hostnames enabled that match this interface
       
   387 
       
   388 	const EDnsQType qt = aIpVer == EIPv4 ? EDnsQType_A : aIpVer == EIPv6 ? EDnsQType_AAAA : EDnsQType(0);
       
   389 
       
   390 	const TInt N = iLlmnrConf->iHostList->Count();
       
   391 	for (TInt i = 0; i < N; i++)
       
   392 		{
       
   393 		const THostNameEntry &host = iLlmnrConf->iHostList->At(i);
       
   394 
       
   395 		if (host.iVersion != EIPany && host.iVersion != aIpVer)
       
   396 			continue;	// Does not apply to this entry, go look next
       
   397 		if (host.iIfName.Length() > 0 && host.iIfName.Compare(aIfName) != 0)
       
   398 			continue;	// Entry is for a specific interface (not this), go look next
       
   399 		//
       
   400 		// Build a new LLMNR entry
       
   401 		//
       
   402 		TInetAddr addr(iControl.GetConfig().iLlmnrPort);
       
   403 		// Give name and address to the server manager
       
   404 		if(aIpVer == EIPv4)
       
   405 			addr.SetAddress(iControl.GetConfig().iLlmnrIpv4);
       
   406 		else
       
   407 			addr.SetAddress(iControl.GetConfig().iLlmnrIpv6);
       
   408 		iServerManager.AddServerAddress(aIfName, addr);
       
   409 
       
   410 		// Make an entry to the list
       
   411 		CLlmnrEntry *entry = new CLlmnrEntry();
       
   412 		if (entry == NULL)
       
   413 			break;	// Ooops, out of memory...
       
   414 		entry->iNext = iEntryList;
       
   415 		iEntryList = entry;
       
   416 
       
   417 		entry->iQuestion.SetName(host.iName);
       
   418 		entry->iQuestion.SetQType(qt);
       
   419 		entry->iQuestion.SetQClass(EDnsQClass_IN);
       
   420 		entry->iVersion = aIpVer;
       
   421 		//
       
   422 		// Copy the scope vector
       
   423 		//
       
   424 		for (TUint k = 0; k < sizeof(TInetScopeIds) / sizeof(entry->iZone[0]); k++)
       
   425 			entry->iZone[k] = aZone[k];
       
   426 
       
   427 		entry->iState = EInactive;
       
   428 		if(FormatHostName(*entry, aHwAddr) == KErrNone)
       
   429 			(void)DoUpdate(*entry);
       
   430 		else
       
   431 			entry->iState = EDisabled;
       
   432 		LOG(LogPrint(_L("\tLLMNR Created: "), *entry));
       
   433 		}
       
   434 	return KErrNone;
       
   435 	}
       
   436 
       
   437 TInt CDndLlmnrResponder::FormatHostName(CLlmnrEntry &aEntry, const TSockAddr &aHwAddr)
       
   438 	{
       
   439 	TInt i;
       
   440 	aEntry.iHostName = 0;
       
   441 	if((i = aEntry.iQuestion.Find(FORMATHWADDR)) != KErrNotFound)
       
   442 		{ // hostname contains hardware address format string
       
   443 		if(aHwAddr.Family() == KAFUnspec)
       
   444 			{
       
   445 			LOG(Log::Printf(_L("CDndLlmnrResponder::FormatHostName - no hw address\r\n")));
       
   446 			return  KErrNotFound;
       
   447 			};
       
   448 
       
   449 		// Insert hw address into hostname
       
   450 		// (We assume, that there is only one hw address insert in the hostname)
       
   451 		TDndName tmpstr;
       
   452 		tmpstr.Append(aEntry.iQuestion.Left(i));
       
   453 		TInt err;
       
   454 		if((err = TRawAddr::Cast(aHwAddr).Append(tmpstr)) != KErrNone)
       
   455 			return err;
       
   456 		tmpstr.Append(aEntry.iQuestion.Mid(i + FORMATHWADDR().Length()));
       
   457 		(TDndName &)aEntry.iQuestion = tmpstr;
       
   458 		return KErrNone;
       
   459 		}
       
   460 	else if((i = aEntry.iQuestion.Compare(WILDCARDPRIMARYHOSTNAME)) == 0)
       
   461 		{
       
   462 		// Entry requests use of local hostname. Find a matching local name
       
   463 		// based on the network id.
       
   464 		aEntry.iHostName = 1;
       
   465 		const TUint32 nid = aEntry.iZone[KIp6AddrScopeNetwork-1];
       
   466 		(void)iHostNames.Refresh(nid);	// Reread hostname from Comms Database.
       
   467 		aEntry.iQuestion.SetName(iHostNames.Find(nid));
       
   468 		return aEntry.iQuestion.Length() > 0 ? KErrNone : KErrNotFound;
       
   469 		}
       
   470 	else
       
   471 		return KErrNone; // No format string in hostname
       
   472 	}
       
   473 
       
   474 
       
   475 void CDndLlmnrResponder::CancelAll(const CLlmnrEntry &aEntry)
       
   476 	{
       
   477 
       
   478 	// Abort all associated requests, if any
       
   479 
       
   480 	for (TInt session = 0; session < KLlmnrMaxSessions; ++session)
       
   481 		if(iLlmnrDataList[session].iLlmnrEntry == &aEntry)
       
   482 			{
       
   483 			iLlmnrDataList[session].iTimeout.Cancel();
       
   484 			iLlmnrDataList[session].Cancel();
       
   485 			iLlmnrDataList[session].iLlmnrEntry = NULL;
       
   486 			}
       
   487 	}
       
   488 
       
   489 
       
   490 TInt CDndLlmnrResponder::DoUpdate(CLlmnrEntry &aEntry)
       
   491 	{
       
   492 	if (JoinMulticastGroup(aEntry.iZone[0], STATIC_CAST(TIpVer, aEntry.iVersion)) != KErrNone)
       
   493 		{
       
   494 		// The interface does not support multicast, disable entry.
       
   495 		LOG(LogPrint(_L("CDndLlmnrResponder::DoUpdate() No multicast, disable: "), aEntry));
       
   496 		aEntry.iState = EDisabled;
       
   497 		return KErrNotSupported;
       
   498 		}
       
   499 	
       
   500 	TInt session = 0;
       
   501 	for(session=0; ; session++)
       
   502 		{
       
   503 		if(session == KLlmnrMaxSessions)
       
   504 			{
       
   505 			LOG(Log::Printf(_L("CDndLlmnrResponder::DoUpdate - No free slots in iLlmnrDataList")));
       
   506 			return KErrNoMemory;
       
   507 			}
       
   508 		if(!iLlmnrDataList[session].iLlmnrEntry)
       
   509 			break;
       
   510 		}
       
   511 	TLlmnrMsgData &upd = iLlmnrDataList[session];
       
   512 	upd.iLlmnrEntry = &aEntry;
       
   513 
       
   514 	// Do Unique check by sending a query for the name, and if nobody answers within
       
   515 	// specified time, assume the name is valid to use for this node.
       
   516 	upd.iQuestion = aEntry.iQuestion;
       
   517 	upd.iQR = 0;
       
   518 	upd.iAA = 0;
       
   519 	upd.iRCode = EDnsRcode_NOERROR;
       
   520 	if (aEntry.iVersion == EIPv4)
       
   521 		upd.iDstAddr.SetAddress(iControl.GetConfig().iLlmnrIpv4);
       
   522 	else
       
   523 		upd.iDstAddr.SetAddress(iControl.GetConfig().iLlmnrIpv6);
       
   524 	upd.iDstAddr.SetScope(aEntry.iZone[upd.iDstAddr.Ip6Address().Scope()-1]);
       
   525 	upd.iDstAddr.SetPort(iControl.GetConfig().iLlmnrPort);
       
   526 	upd.iRepeat = 1 + iControl.GetConfig().iLlmnrRetries;
       
   527 	Queue(upd);
       
   528 	return KErrNone;
       
   529 	}
       
   530 
       
   531 void CDndLlmnrResponder::Query(const TMsgBuf &aBuf, const TInetAddr &aServer, const RSocket &aSocket)
       
   532 	{
       
   533 	ASSERT(aServer.Port() != 0);
       
   534 
       
   535 	// Preselect the the session...
       
   536 	TInt session = 0;
       
   537 	for(;; session++)
       
   538 		{
       
   539 		if(session == KLlmnrMaxSessions)
       
   540 			{
       
   541 			LOG(Log::Printf(_L("\tLLMNR No free slots in iLlmnrDataList\r\n")));
       
   542 			return;
       
   543 			}
       
   544 		if(!iLlmnrDataList[session].iLlmnrEntry)
       
   545 			break;
       
   546 		}
       
   547 	TLlmnrMsgData &resp = iLlmnrDataList[session];
       
   548 	TInt rcode;
       
   549 	TInt offset = aBuf.VerifyMessage(rcode, resp.iQuestion);
       
   550 	if (offset < 0)
       
   551 		{
       
   552 		LOG(Log::Printf(_L("\tLLMNR Corrupt message\r\n")));
       
   553 		return; // A corrupted message
       
   554 		}
       
   555 	const TDndHeader &hdr = aBuf.Header();
       
   556 	if (hdr.QR() || hdr.ANCOUNT() != 0)
       
   557 		return;	// This is responce, Not a query. Ignore.
       
   558 
       
   559 	CLlmnrEntry *entry = iEntryList;
       
   560 	TUint32 index = 0;
       
   561 
       
   562 	// Note: there are other PTR queries than just for address!
       
   563 	// (fall to normal query processing for non address PTR queries).
       
   564 	if (resp.iQuestion.QType() == EDnsQType_PTR &&
       
   565 		(index = IsMyAddress(resp.iQuestion)) != 0)
       
   566 		{
       
   567 		// See if this interface is active...
       
   568 		for(;; entry = entry->iNext)
       
   569 			{
       
   570 			if (entry == NULL)
       
   571 				{
       
   572 				LOG(LogPrint(_L("\tLLMNR No match: "), resp.iQuestion));
       
   573 				return; // No match, ignore
       
   574 				}
       
   575 			if (entry->iState > 0)
       
   576 				{
       
   577 				if (entry->iZone[0] == index)
       
   578 					break;
       
   579 				}
       
   580 			}
       
   581 		}
       
   582 	else
       
   583 		{
       
   584 
       
   585 		// The question must match one of the entries
       
   586 
       
   587 		const TInt scopelevel = aServer.Ip6Address().Scope()-1;
       
   588 		const TUint32 scopeid = aServer.Scope();
       
   589 		for(CLlmnrEntry *my_name = NULL; ;entry = entry->iNext)
       
   590 			{
       
   591 			if (entry == NULL)
       
   592 				{
       
   593 				if (my_name == NULL)
       
   594 					{
       
   595 					LOG(LogPrint(_L("\tLLMNR Query does not match: "), resp.iQuestion));
       
   596 					return; // No match, ignore
       
   597 					}
       
   598 				//
       
   599 				// No exact match to the query, but the name
       
   600 				// matched to at least one of my unique names.
       
   601 				// Reply with empty RR-set, using one of those entries.
       
   602 				entry = my_name;
       
   603 				break;
       
   604 				}
       
   605 			// A iState > 0 means valid entry.
       
   606 			if (entry->iState > 0)
       
   607 				{
       
   608 				if (scopeid == entry->iZone[scopelevel])
       
   609 					{
       
   610 					if (DnsCompareNames(resp.iQuestion, entry->iQuestion))
       
   611 						{
       
   612 						my_name = entry;
       
   613 						if (resp.iQuestion.QClass() == entry->iQuestion.QClass() &&
       
   614 							resp.iQuestion.QType() == entry->iQuestion.QType())
       
   615 							break;	// Full Match, answer using this entry!
       
   616 						}
       
   617 					}
       
   618 				}
       
   619 			}
       
   620 		}
       
   621 	//
       
   622 	// Actually answering the question, assign the request
       
   623 	//
       
   624 	LOG(LogPrint(_L("\tLLMNR Sending reply to matched query: "), *entry));
       
   625 	resp.iLlmnrEntry = entry;
       
   626 	resp.iQR = 1;
       
   627 	resp.iAA = 1;
       
   628 	resp.iRCode = EDnsRcode_NOERROR;
       
   629 	resp.iDstAddr = aServer;
       
   630 	resp.iRepeat = 0;
       
   631 	Queue(resp, aSocket, hdr.ID());
       
   632 	}
       
   633 
       
   634 
       
   635 TUint32 CDndLlmnrResponder::IsMyAddress(const TDndQuestion &aQuestion)
       
   636 	{
       
   637 	TPckgBuf<TSoInetIfQuery> opt;
       
   638 	if (!aQuestion.GetAddress(opt().iSrcAddr))
       
   639 		return 0;	// Not a parsable PTR for IP address, ignore.
       
   640 	if(Socket().GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, opt) != KErrNone)
       
   641 		return 0;// not my address, ignore
       
   642 	return opt().iIndex;
       
   643 	}
       
   644 
       
   645 TInt CDndLlmnrResponder::SetHostName(TUint32 aId, const TDesC &aName)
       
   646 	{
       
   647 	for (CLlmnrEntry *e = iEntryList; e; e = e->iNext)
       
   648 		{
       
   649 		if (e->iHostName && e->iZone[KIp6AddrScopeNetwork-1] == aId)
       
   650 			{
       
   651 			if (aName.Length() > 0)
       
   652 				{
       
   653 				e->iState = EInactive;
       
   654 				e->iQuestion.SetName(aName);
       
   655 				(void)DoUpdate(*e);
       
   656 				}
       
   657 			else
       
   658 				{
       
   659 				e->iState = EDisabled;
       
   660 				CancelAll(*e);
       
   661 				}
       
   662 			}
       
   663 		}
       
   664 	return KErrNone;
       
   665 	}
       
   666 
       
   667 
       
   668 TInt CDndLlmnrResponder::GetHostName(TUint32 aId, MDnsResolver &aCallback)
       
   669 	{
       
   670 	const TInt result = DoHostNameState(aId);
       
   671 
       
   672 	if (result > 0)
       
   673 		{
       
   674 		//
       
   675 		// Pending entries present, install callback
       
   676 		//
       
   677 		for (CHostCallback *c = iCallbacks; ; c = c->iNext)
       
   678 			{
       
   679 			if (c == NULL)
       
   680 				{
       
   681 				c = new CHostCallback(aCallback);
       
   682 				if (c == NULL)
       
   683 					return KErrNoMemory;
       
   684 				c->iNext = iCallbacks;
       
   685 				iCallbacks = c;
       
   686 				break;
       
   687 				}
       
   688 			else if (&aCallback == &c->iCallback)
       
   689 				break;	// Already installed.
       
   690 			}
       
   691 		}
       
   692 	return result;
       
   693 	}
       
   694 
       
   695 
       
   696 
       
   697 /**
       
   698 * Determines the state of the hostname.
       
   699 *
       
   700 * Scans through all LLMNR names and checks state of the
       
   701 * entries that have been generated from the host name.
       
   702 * Ignore entries in EDisabled state.
       
   703 *
       
   704 * @return result as follows:
       
   705 *
       
   706 * - KErrNone, if all existing entries are currently
       
   707 * marked as "unique" (note: this includes the case,
       
   708 * where none of the names are generated from the
       
   709 * host name). No entry is in conflict state.
       
   710 * - KErrAlreadyExists, if at least one of the entries
       
   711 * is in conflict.
       
   712 * - = 1 (Pending), if at least one of the entries is
       
   713 * still being tested for uniqueness, and none of the
       
   714 * entries is in conflict.
       
   715 */
       
   716 TInt CDndLlmnrResponder::DoHostNameState(TUint32 aId)
       
   717 	{
       
   718 	TInt result = KErrNone;
       
   719 	for (CLlmnrEntry *e = iEntryList; e; e = e->iNext)
       
   720 		{
       
   721 		if (e->iZone[KIp6AddrScopeNetwork-1] == aId && e->iHostName)
       
   722 			{
       
   723 			if (e->iState == EInactive)
       
   724 				{
       
   725 				// Pending state, unique test not yet complete
       
   726 				result = 1;
       
   727 				}
       
   728 			else if (e->iState == EConflict)
       
   729 				{
       
   730 				// Conflict state, assume a name collision has occurred
       
   731 				return KErrAlreadyExists;
       
   732 				}
       
   733 			}
       
   734 		}
       
   735 	return result;
       
   736 	}
       
   737 
       
   738 /**
       
   739 * Do callbacks for pending GetHostName.
       
   740 *
       
   741 * Determines the state of the hostname and does the
       
   742 * callbacks, if the state is not pending.
       
   743 */
       
   744 void CDndLlmnrResponder::DoCallbacks(TUint32 aId)
       
   745 	{
       
   746 	if (iCallbacks == NULL)
       
   747 		return;
       
   748 
       
   749 	const TInt result = DoHostNameState(aId);
       
   750 	if (result > 0)
       
   751 		return;
       
   752 
       
   753 	CHostCallback *c = iCallbacks;
       
   754 	iCallbacks = NULL;
       
   755 	while (c)
       
   756 		{
       
   757 		CHostCallback *cb = c;
       
   758 		c = cb->iNext;
       
   759 		cb->iCallback.ReplyCallback(result);
       
   760 		delete cb;
       
   761 		}
       
   762 	}
       
   763 
       
   764 //****************** TLlmnrMsgData ****************************
       
   765 
       
   766 // constructor needed only to setup the timeout framework
       
   767 TLlmnrMsgData::TLlmnrMsgData() : iTimeout(TLlmnrMsgDataTimeoutLinkage::Timeout)
       
   768 	{
       
   769 	}
       
   770 
       
   771 void TLlmnrMsgData::Timeout(const TTime & /*aNow*/)
       
   772 	{
       
   773 	LOG(Log::Printf(_L("--> TLlmnrMsgData::Timeout() -start-\r\n")));
       
   774 	if (iLlmnrEntry)
       
   775 		{
       
   776 		if (iRepeat > 0)
       
   777 			{
       
   778 			LOG(iParent->LogPrint(_L("\tLLMNR Resend query: "), *iLlmnrEntry));
       
   779 			iParent->ReSend(*this);
       
   780 			}
       
   781 		else
       
   782 			{
       
   783 			Cancel();
       
   784 			// The timeout is only activated with Unique testing, thus
       
   785 			// when final repeat has copleted without conflict, mark
       
   786 			// entry as unique
       
   787 			LOG(iParent->LogPrint(_L("\tLLMNR Name is unique: "), *iLlmnrEntry));
       
   788 			iLlmnrEntry->iState = EUnique;
       
   789 			if (iLlmnrEntry->iHostName)
       
   790 				{
       
   791 				// If entry depended on the hostname and there are pending GetHostNames,
       
   792 				// then check if this was the last such entry in pending state, and
       
   793 				// if so, generate callbacks.
       
   794 				iParent->DoCallbacks(iLlmnrEntry->iZone[KIp6AddrScopeNetwork-1]);
       
   795 				}
       
   796 			iLlmnrEntry = NULL;
       
   797 			}
       
   798 		}
       
   799 	LOG(Log::Printf(_L("<-- TLlmnrMsgData::Timeout() -exit-\r\n")));
       
   800 	}
       
   801 
       
   802 TBool TLlmnrMsgData::Reply(CDnsSocket &aSource, const TMsgBuf &aBuf, const TInetAddr & /*aServer*/)
       
   803 	{
       
   804 	if (!iLlmnrEntry)
       
   805 		return FALSE;			// Nothing to do if no entry associated
       
   806 
       
   807 	TDndQuestion question;
       
   808 	TInt rcode;
       
   809 	TInt offset = aBuf.VerifyMessage(rcode, question);
       
   810 	if (offset <= 0)
       
   811 		return FALSE;
       
   812 
       
   813 	const TDndHeader &hdr = aBuf.Header();
       
   814 	if (!hdr.QR())
       
   815 		return FALSE;	// This is query, not a response. Ignore.
       
   816 	if (hdr.OPCODE() != EDnsOpcode_QUERY || rcode != EDnsRcode_NOERROR)
       
   817 		return FALSE;	// Not an OK reply
       
   818 
       
   819 	if (question.CheckQuestion(iQuestion) != KErrNone)
       
   820 		return FALSE;
       
   821 
       
   822 	// This is a matching reply to query of our own name, there is
       
   823 	// a collision.
       
   824 	iLlmnrEntry->iState = EConflict;
       
   825 	if (iLlmnrEntry->iHostName)
       
   826 		iParent->DoCallbacks(iLlmnrEntry->iZone[KIp6AddrScopeNetwork-1]);
       
   827 	CNotifyConflict::Start(*iParent, *iLlmnrEntry);
       
   828 
       
   829 	Cancel();
       
   830 	CDndLlmnrResponder &responder = (CDndLlmnrResponder &)aSource;
       
   831 	responder.CancelAll(*iLlmnrEntry);
       
   832 	return TRUE;
       
   833 	}
       
   834 
       
   835 
       
   836 void TLlmnrMsgData::Sent(CDnsSocket &/*aSource*/)
       
   837 	{
       
   838 	if (iRepeat == 0)
       
   839 		{
       
   840 		iLlmnrEntry = NULL;
       
   841 		Cancel();
       
   842 		}
       
   843 	else
       
   844 		{
       
   845 		iRepeat -= 1;
       
   846 		iTimeout.Set(&iParent->iControl.Timer(), iParent->iControl.GetConfig().iLlmnrMinTime);
       
   847 		}
       
   848 	}
       
   849 
       
   850 void TLlmnrMsgData::Abort(CDnsSocket &/*aSource*/, const TInt aReason)
       
   851 	{
       
   852 	LOG(Log::Printf(_L("TLlmnrMsgData::Abort - reason: %d\r\n"),aReason));
       
   853 	(void)aReason; // silence compiler warning
       
   854 	iLlmnrEntry = NULL;
       
   855 	}
       
   856 
       
   857 // TLlmnrMsgData::Build
       
   858 // ******************
       
   859 /**
       
   860 // @retval	aMsg
       
   861 //		contains the fully constructed message to be sent to the DNS server,
       
   862 //		if Build succeeds
       
   863 // @retval	aServer
       
   864 //		contains the server address for which the message should be sent
       
   865 //
       
   866 // @returns TRUE, successful Build, and error (< 0) otherwise
       
   867 */
       
   868 TBool TLlmnrMsgData::Build(CDnsSocket &/*aSource*/, TMsgBuf &aMsg, TInetAddr &aServer, TInt /*aMaxMessage*/)
       
   869 	{
       
   870 	TInt ret = KErrNone;
       
   871 	for (;;)
       
   872 		{
       
   873 		if (iLlmnrEntry == NULL)
       
   874 			{
       
   875 			LOG(Log::Printf(_L("TLlmnrMsgData::Build() - Faulty component\r\n")));
       
   876 			ret = KErrArgument;
       
   877 			break;
       
   878 			}
       
   879 
       
   880 		aServer = iDstAddr;
       
   881 		aMsg.SetLength(sizeof(TDndHeader));
       
   882 		TDndHeader &hdr = (TDndHeader &)aMsg.Header();
       
   883 		hdr.SetRD(0); // Part of zero field
       
   884 		hdr.SetOpcode(EDnsOpcode_QUERY);
       
   885 		hdr.SetQR(iQR);
       
   886 		hdr.SetAA(iAA);
       
   887 		hdr.SetRCode(iRCode);
       
   888 		hdr.SetQdCount(1);
       
   889 		const TInt qname_offset = aMsg.Length();
       
   890 		ret = iQuestion.Append(aMsg);
       
   891 		if (ret != KErrNone)
       
   892 			break;
       
   893 
       
   894 		if (iQR)
       
   895 			{
       
   896 			// This is a reply message
       
   897 			TDndRROut rr(aMsg);
       
   898 			rr.iType = (TUint16)iQuestion.QType();
       
   899 			rr.iClass = (TUint16)iQuestion.QClass();
       
   900 			rr.iTTL = iParent->iLlmnrConf->iTTL;
       
   901 
       
   902 			if (rr.iType == EDnsType_PTR)
       
   903 				{
       
   904 				// answer contains one or several hostnames, which
       
   905 				// are configured for the same interface as the
       
   906 				// queried address.
       
   907 				TUint16 count = 0;
       
   908 				for(CLlmnrEntry *entry = iParent->iEntryList; entry != NULL; entry = entry->iNext)
       
   909 					{
       
   910 					if (entry->iState <= 0)
       
   911 						continue;
       
   912 					if (entry->iZone[0] != iLlmnrEntry->iZone[0])
       
   913 						continue;
       
   914 					//
       
   915 					// Build an RR
       
   916 					//
       
   917 					ret = rr.Append(KNullDesC8, qname_offset);
       
   918 					if (ret != KErrNone)
       
   919 						break; // -- no reply sent!
       
   920 					ret = rr.AppendRData(entry->iQuestion, 0);
       
   921 					if (ret != KErrNone)
       
   922 						break; // -- no reply sent!
       
   923 					count++;
       
   924 					}
       
   925 				hdr.SetAnCount(count); // set answer or prerequisite count
       
   926 				}
       
   927 			else if (iQuestion.QType() == EDnsQType_ANY)
       
   928 				{
       
   929 				// For ANY query, return one address
       
   930 				// (experimental, not fully worked out yet)
       
   931 				TUint16 count = 0;
       
   932 				TInetAddr addr;
       
   933 				rr.iType = EDnsType_A;
       
   934 				ret = iParent->MakeMyAddr(iLlmnrEntry->iZone[0], iDstAddr, (EDnsType)rr.iType, addr);
       
   935 				if (ret != KErrNone)
       
   936 					break;
       
   937 				if (!addr.IsUnspecified())
       
   938 					{
       
   939 					ret = rr.Append(KNullDesC8, qname_offset);// compressed name and answer
       
   940 					if (ret != KErrNone)
       
   941 						ret = rr.AppendRData(addr);
       
   942 					++count;
       
   943 					}
       
   944 				rr.iType = EDnsType_AAAA;
       
   945 				ret = iParent->MakeMyAddr(iLlmnrEntry->iZone[0], iDstAddr, (EDnsType)rr.iType, addr);
       
   946 				if (ret != KErrNone)
       
   947 					break;
       
   948 				if (!addr.IsUnspecified())
       
   949 					{
       
   950 					ret = rr.Append(KNullDesC8, qname_offset);// compressed name and answer
       
   951 					if (ret != KErrNone)
       
   952 						ret = rr.AppendRData(addr);
       
   953 					++count;
       
   954 					}
       
   955 				hdr.SetAnCount(count);
       
   956 				}
       
   957 			else if (iQuestion.QType() != iLlmnrEntry->iQuestion.QType())
       
   958 				{
       
   959 				// The question and entry do not match. Assume this is
       
   960 				// query for RR that we don't have, but the name matched.
       
   961 				// Reply with empty RR-set.
       
   962 				hdr.SetAnCount(0);
       
   963 				}
       
   964 			else if (rr.iType == EDnsType_A || rr.iType == EDnsType_AAAA)
       
   965 				{
       
   966 				// answer contains one address
       
   967 				TInetAddr addr;
       
   968 				ret = iParent->MakeMyAddr(iLlmnrEntry->iZone[0], iDstAddr, (EDnsType)rr.iType, addr);
       
   969 				if (ret != KErrNone)
       
   970 					break;
       
   971 				if (addr.IsUnspecified())
       
   972 					hdr.SetAnCount(0);	// No address
       
   973 				else
       
   974 					{
       
   975 					ret = rr.Append(KNullDesC8, qname_offset);// compressed name and answer
       
   976 					if (ret == KErrNone)
       
   977 						ret = rr.AppendRData(addr);
       
   978 					hdr.SetAnCount(1); // set answer count
       
   979 					}
       
   980 				}
       
   981 			else
       
   982 				break;	// Unsupported RR type, no answer!
       
   983 			}
       
   984 		if (ret != KErrNone)
       
   985 			break;
       
   986 		return 1;
       
   987 		}
       
   988 	//
       
   989 	// Failed to build the message
       
   990 	//
       
   991 	iLlmnrEntry = NULL;
       
   992 	Cancel();
       
   993 	return 0;
       
   994 	}
       
   995 
       
   996 
       
   997 // **********************************************************************
       
   998 
       
   999 CNotifyConflict::CNotifyConflict(CDndLlmnrResponder &aResponder, CLlmnrEntry &aEntry)
       
  1000 	: CActive(0), iResponder(aResponder), iEntry(aEntry)
       
  1001 	{
       
  1002 	LOG(Log::Printf(_L("\tnotifier[%u] new"), (TUint)this));
       
  1003 	CActiveScheduler::Add(this);
       
  1004 	}
       
  1005 
       
  1006 CNotifyConflict::~CNotifyConflict()
       
  1007 	{
       
  1008 	Cancel();
       
  1009 	if (iConnected)
       
  1010 		{
       
  1011 		iNotifier.Close();
       
  1012 		}
       
  1013 
       
  1014 	// Detach from the entry.
       
  1015 	if (iEntry.iNotify == this)
       
  1016 		iEntry.iNotify = NULL;
       
  1017 	// Deque from the active scheduler
       
  1018 	if (IsAdded())
       
  1019 		Deque();
       
  1020 	LOG(Log::Printf(_L("\tnotifier[%u] deleted"), (TUint)this));
       
  1021 	}
       
  1022 
       
  1023 void CNotifyConflict::Start(CDndLlmnrResponder &aResponder, CLlmnrEntry &aEntry)
       
  1024 	{
       
  1025 	if (aEntry.iNotify)
       
  1026 		{
       
  1027 		return;			// Notify process is already active for this hostname, nothing to do.
       
  1028 		}
       
  1029 	aEntry.iNotify = new CNotifyConflict(aResponder, aEntry);
       
  1030 	if (aEntry.iNotify)
       
  1031 		{
       
  1032 		aEntry.iNotify->DoStart();
       
  1033 		}
       
  1034 	}
       
  1035 
       
  1036 void CNotifyConflict::DoStart()
       
  1037 	{
       
  1038 	if (iNotifier.Connect() == KErrNone)
       
  1039 		{
       
  1040 		iConnected = 1;
       
  1041 		// Fill in information
       
  1042 		iInfo().iIAPId = iEntry.iZone[1];		// IAP is iZone[1]
       
  1043 		iInfo().iNetworkId = iEntry.iZone[15];	// NET is iZone[15]
       
  1044 		(void)iEntry.iQuestion.GetName(iInfo().iName);
       
  1045 		LOG(Log::Printf(_L("\tnotifier[%u] activated IAP=%d NET=%d HOST='%S'"), (TUint)this,
       
  1046 			iInfo().iIAPId, iInfo().iNetworkId, &iInfo().iName));
       
  1047 		iNotifier.StartNotifierAndGetResponse(iStatus, TUid::Uid(KLlmnrConflictNotifyUid), iInfo, iInfo);
       
  1048 		SetActive();
       
  1049 		}
       
  1050 	else
       
  1051 		{
       
  1052 		// Cancel Notifier activity, cannot get it to work.
       
  1053 		delete this;
       
  1054 		}
       
  1055 	}
       
  1056 
       
  1057 void CNotifyConflict::DoCancel()
       
  1058 	{
       
  1059 	LOG(Log::Printf(_L("\tnotifier[%u] canceling"), (TUint)this));
       
  1060 	iNotifier.CancelNotifier(TUid::Uid(KLlmnrConflictNotifyUid));
       
  1061 	}
       
  1062 
       
  1063 void CNotifyConflict::RunL()
       
  1064 	{
       
  1065 	LOG(Log::Printf(_L("-->\tnotifier[%u] Completion result=%d"), (TUint)this, iStatus.Int()));
       
  1066 	if (iStatus.Int() == KErrNone && iInfo().IsSafe() && iInfo().iName.Length() > 0)
       
  1067 		{
       
  1068 		if (iEntry.iQuestion.SetName(iInfo().iName) == KErrNone)
       
  1069 			{
       
  1070 			LOG(Log::Printf(_L("-->\tnotifier[%u] Trying new name '%S'"), (TUint)this, &iInfo().iName));
       
  1071 			iEntry.iState = EInactive;
       
  1072 			// Detach from the entry.
       
  1073 			if (iEntry.iNotify == this)
       
  1074 				iEntry.iNotify = NULL;
       
  1075 			(void)iResponder.DoUpdate(iEntry);
       
  1076 			}
       
  1077 		}
       
  1078 	delete this;
       
  1079 	}
       
  1080 
       
  1081 #endif