tcpiputils/dnd/src/servers.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 // servers.cpp - server manager module
       
    15 //
       
    16 
       
    17 #include "servers.h"
       
    18 #include "engine.h"
       
    19 #include "inet6log.h"
       
    20 #include "dns_hdr.h"	// only for KDnsPort!
       
    21 #include "dnd.hrh"
       
    22 
       
    23 // Item of the server list, hold DNS server information
       
    24 class TDnsServerData
       
    25 	{
       
    26 public:
       
    27 	TInetAddr iAddr;			//< DNS Server Address
       
    28 	TDnsServerScope iScope;		//< The Sever Scope and type (MC/UC)
       
    29 	TInt iServerId;				//< Id of the server
       
    30 	TInt iInterface;			//< Index to Interface Array
       
    31 	};
       
    32 
       
    33 // Item of the interface list, hold interface information for DNS
       
    34 class TDnsInterfaceData
       
    35 	{
       
    36 public:
       
    37 	TName iName;				//< Name of the interface
       
    38 	TUint32 iScope[16];			//< The scope vector
       
    39 	};
       
    40 
       
    41 // Item of the configured servers list
       
    42 class TDnsConfiguredServer
       
    43 	{
       
    44 public:
       
    45 	TName iName;
       
    46 	TInetAddr iAddr;
       
    47 	};
       
    48 
       
    49 class CDnsServerManager : public CBase, public MDnsServerManager
       
    50 	{
       
    51 	~CDnsServerManager();
       
    52 public:
       
    53 	CDnsServerManager(CDndEngine &aControl);
       
    54 	void ConstructL();
       
    55 	void ConfigurationChanged();
       
    56 
       
    57 	//
       
    58 	// MDnsServerManager API
       
    59 	// (for docs, see the MDnsServerManger definitions)
       
    60 	//
       
    61 	TInt OpenList(const TDnsServerFilter &aFilter, MDnsServerListNotify *aNotify);
       
    62 	TInt Count(const TDnsServerFilter &aFilter) const;
       
    63 	TInt Next(const TDnsServerFilter &aFilter, TInt aServerId) const;
       
    64 	void CloseList(const TDnsServerFilter &aFilter);
       
    65 
       
    66 	TInt Address(TInt aServerId, TInetAddr &aAddr) const;
       
    67 	TUint32 Scope(TInt aServerId, const TInetAddr &aAddr);
       
    68 	TInt ServerId(const TInetAddr &aAddr) const;
       
    69 	TUint32 NameSpace(const TDnsServerFilter &aFilter, TInt aServerId) const;
       
    70 	TInt BuildServerList();
       
    71 	void AddServerAddress(const TName &aInterface, const TInetAddr &aAddr);
       
    72 	void LockByAddress(const TInetAddr &aAddr, TUint32 aNid, TDnsServerFilter &aFilter);
       
    73 
       
    74 private:
       
    75 	// Build and add interface entry to the list (basic operation)
       
    76 	TInt AddInterfaceEntry(const TSoInetIfQuery &aInfo);
       
    77 	// Find interface matching the destination address
       
    78 	TInt FindInterface(const TInetAddr &aAddr);
       
    79 	// Add new server address to the server list
       
    80 	void AddToServerList(const TInetAddr &aAddr, TInt aIf, RSocket &aSocket);
       
    81 	// Add new interface to the interface list
       
    82 	TInt AddToInterfaceList(const TSoInetInterfaceInfo &aInfo, RSocket &aSocket);
       
    83 	// Compare the filter with a DNS server
       
    84 	TBool Match(const TDnsServerFilter &aFilter, const TDnsServerData &aServer) const;
       
    85 
       
    86 	CDndEngine &iControl;
       
    87 	TUint32 iServerId;				//< The last used server id.
       
    88 	TTime iMark;					//< The time of the last configuration change.
       
    89 	TUint iConfigure:1;				//< Reconfigure needed, if set.
       
    90 	TUint iStable:1;				//< = 1, when scanned list is supposed to be stable
       
    91 	TUint iCacheFlushed:1;			//< = 1, when cache has been flushed (only used with "FlushOnConfig" ini-option)
       
    92 
       
    93 	CArrayFixFlat<TDnsServerData> *iServerList;	//< Current list of servers
       
    94 	CArrayFixFlat<TDnsInterfaceData> *iInterfaceList; //< Current list of interfaces
       
    95 	CArrayFixFlat<TDnsConfiguredServer> *iConfiguredList; //< Current list of configured servers
       
    96 	};
       
    97 
       
    98 
       
    99 MDnsServerManager *DnsServerManager::NewL(CDndEngine &aControl)
       
   100 	{
       
   101 	CDnsServerManager *mgr = new (ELeave) CDnsServerManager(aControl);
       
   102 
       
   103 	CleanupStack::PushL(mgr);
       
   104 	mgr->ConstructL();
       
   105 	CleanupStack::Pop();
       
   106 	return mgr;
       
   107 	}
       
   108 
       
   109 //
       
   110 // CDnsServerManager
       
   111 //
       
   112 
       
   113 CDnsServerManager::CDnsServerManager(CDndEngine &aControl) : iControl(aControl)
       
   114 	{
       
   115 	}
       
   116 
       
   117 void CDnsServerManager::ConstructL()
       
   118 	{
       
   119 	iServerList = new (ELeave) CArrayFixFlat<TDnsServerData>(2);
       
   120 	iInterfaceList = new (ELeave) CArrayFixFlat<TDnsInterfaceData>(5);
       
   121 	// iConfiguredList is allocated only if required.
       
   122 	}
       
   123 
       
   124 void CDnsServerManager::ConfigurationChanged()
       
   125 	{
       
   126 	LOG(Log::Printf(_L("CDnsServerManager -- Configuration changed")));
       
   127 	// Just flag that building a new server list is needed. Try
       
   128 	// to delay heavy interface scanning operation until really
       
   129 	// needed (because configuration changes may come in burts).
       
   130 	iConfigure = 1;
       
   131 	iStable = 0;
       
   132 	iCacheFlushed = 0;
       
   133 	iMark.UniversalTime();
       
   134 	}
       
   135 
       
   136 CDnsServerManager::~CDnsServerManager()
       
   137 	{
       
   138 	delete iServerList;
       
   139 	delete iInterfaceList;
       
   140 	delete iConfiguredList;
       
   141 	}
       
   142 
       
   143 // CDnsServerManager::AddInterfaceData
       
   144 TInt CDnsServerManager::AddInterfaceEntry(const TSoInetIfQuery &aInfo)
       
   145 	{
       
   146 	TRAPD(err,
       
   147 		TDnsInterfaceData &ifd = iInterfaceList->ExtendL();
       
   148 		ifd.iName = aInfo.iName;
       
   149 		for (TInt i = sizeof(ifd.iScope) / sizeof(ifd.iScope[0]); --i >= 0; )
       
   150 			ifd.iScope[i] = aInfo.iZone[i];
       
   151 		);
       
   152 	return err < 0 ? err : iInterfaceList->Count() - 1;
       
   153 	}
       
   154 
       
   155 // CDnsServerManager::AddToInterfaceList
       
   156 // *************************************
       
   157 /**
       
   158 // Add the interface to the interface list, if it does not already exist.
       
   159 // The existence is based on comparing the interface names.
       
   160 //
       
   161 // @param	aInfo	the information that identifies the interface
       
   162 // @param	aSocket	(must be open) to be used for GetOpt, if needed
       
   163 // @returns
       
   164 //	@li	< 0, if there are some errors (interface was not added)
       
   165 //	@li index to the interface (>= 0) in the interface list.
       
   166 */
       
   167 TInt CDnsServerManager::AddToInterfaceList(const TSoInetInterfaceInfo &aInfo, RSocket &aSocket)
       
   168 	{
       
   169 	if (aInfo.iName.Length() == 0)
       
   170 		return -1;	// Interface must have a name.
       
   171 	//
       
   172 	// Check if interface already exists and don't insert duplicates
       
   173 	//
       
   174 	TInt i;
       
   175 	for (i = iInterfaceList->Count(); --i >= 0; )
       
   176 		{
       
   177 		const TDnsInterfaceData &data = iInterfaceList->At(i);
       
   178 		if (data.iName.Compare(aInfo.iName) == 0)
       
   179 			return i;	// Interface already present in the list
       
   180 		}
       
   181 	//
       
   182 	// A new interface, get the scope vector
       
   183 	//
       
   184 	TPckgBuf<TSoInetIfQuery> opt;
       
   185 	opt().iName = aInfo.iName;
       
   186 	const TInt err = aSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, opt);
       
   187 	return err < 0 ? err : AddInterfaceEntry(opt());
       
   188 	}
       
   189 
       
   190 // CDnsServerManager::FindInterface
       
   191 // ********************************
       
   192 //
       
   193 TInt CDnsServerManager::FindInterface(const TInetAddr &aAddr)
       
   194 	{
       
   195 	TPckgBuf<TSoInetIfQuery> opt;
       
   196 	opt().iDstAddr = aAddr;
       
   197 	const TInt err = iControl.iSocket.GetOpt(KSoInetIfQueryByDstAddr, KSolInetIfQuery, opt);
       
   198 	if (err < 0)
       
   199 		return err;
       
   200 
       
   201 	// Check if interface is already known
       
   202 
       
   203 	for (TInt i = iInterfaceList->Count(); --i >= 0; )
       
   204 		{
       
   205 		const TDnsInterfaceData &data = iInterfaceList->At(i);
       
   206 		if (data.iName.Compare(opt().iName) == 0)
       
   207 			return i;
       
   208 		}
       
   209 	// Not present yet, just add it
       
   210 	return AddInterfaceEntry(opt());
       
   211 	}
       
   212 
       
   213 // CDnsServerManager::AddToServerList
       
   214 // **********************************
       
   215 /**
       
   216 // Add new address to the server list. A new entry is only
       
   217 // added if the address does not already exist.
       
   218 //
       
   219 // @param	aAddr	address of the DNS server
       
   220 // @param	aIf		the interface (index to the interface list)
       
   221 */
       
   222 void CDnsServerManager::AddToServerList(const TInetAddr &aAddr, TInt aIf, RSocket &aSocket)
       
   223 	{
       
   224 	if (aAddr.IsUnspecified())
       
   225 		return;		// No address, nothing to add
       
   226 	//
       
   227 	// Normalize all addresses into IPv6 format
       
   228 	//
       
   229 	TDnsServerData sd;
       
   230 	sd.iAddr = aAddr;
       
   231 	sd.iInterface = aIf;
       
   232 	if (sd.iAddr.Family() == KAfInet)
       
   233 		sd.iAddr.ConvertToV4Mapped();
       
   234 	else if (sd.iAddr.Family() != KAfInet6)
       
   235 		return;		// Only IPv4 or IPv6 addresses are valid
       
   236 	if (sd.iAddr.IsMulticast())
       
   237 		//	sd.iScope = (TDnsServerScope)(sd.iAddr.Ip6Address().Scope());
       
   238 		sd.iScope = EDnsServerScope_MC_LOCAL;
       
   239 	else
       
   240 		sd.iScope = EDnsServerScope_UC_GLOBAL;
       
   241 
       
   242 	if (!sd.iAddr.Port())
       
   243 		sd.iAddr.SetPort(KDnsPort);
       
   244 
       
   245 	LOG(TBuf<80> dst);
       
   246 	LOG(sd.iAddr.OutputWithScope(dst));
       
   247 	LOG(TBuf<80> src);
       
   248 	// In typhoon and later, DND never activates interfaces. All
       
   249 	// usable server addresses must have a valid route, before
       
   250 	// they can be used. Thus, check it...
       
   251 	//
       
   252 	TPckgBuf<TSoInetIfQuery> opt;
       
   253 	opt().iDstAddr = aAddr;
       
   254 	const TBool has_route =
       
   255 		(aSocket.GetOpt(KSoInetIfQueryByDstAddr, KSolInetIfQuery, opt) == KErrNone) && !opt().iSrcAddr.IsUnspecified();
       
   256 	LOG(opt().iSrcAddr.OutputWithScope(src));
       
   257 	if (!has_route)
       
   258 		{
       
   259 		LOG(Log::Printf(_L("\t\tnameserver [%S] (src=%S) has no route or no source address, skipped"), &dst, &src));
       
   260 		return;				// No route, unusable for now -- ignore
       
   261 		}
       
   262 	//
       
   263 	// Check if address already exists and don't insert duplicates
       
   264 	//
       
   265 	for (TInt i = iServerList->Count(); --i >= 0; )
       
   266 		{
       
   267 		TDnsServerData &a = iServerList->At(i);
       
   268 		if (a.iAddr.Match(sd.iAddr) && a.iAddr.Scope() == sd.iAddr.Scope())
       
   269 			{
       
   270 			// However, if server didn't have assigned
       
   271 			// interface yet, assign it from this call.
       
   272 			//
       
   273 			if (a.iInterface < 0)
       
   274 				a.iInterface = aIf;
       
   275 			LOG(Log::Printf(_L("\t\tnameserver (id=%d) [%S] (src=%S)"), a.iServerId, &dst, &src));
       
   276 			return;	// Duplicate address, do not add again.
       
   277 			}
       
   278 		}
       
   279 
       
   280 	sd.iServerId = ++iServerId;	// Assign a "server id"
       
   281 	LOG(Log::Printf(_L("\t\tnameserver (id=%d) [%S] (src=%S) (new)"), sd.iServerId, &dst, &src));
       
   282 	TRAP_IGNORE(iServerList->AppendL(sd));
       
   283 	}
       
   284 
       
   285 // CDnsServerManager::BuildServerList
       
   286 // **********************************
       
   287 TInt CDnsServerManager::BuildServerList()
       
   288 	{
       
   289 	LOG(Log::Printf(_L("CDnsServerManager -- Scanning interfaces and building the server list")));
       
   290 	TInt err = KErrNone;
       
   291 
       
   292 	// Refresh the current list of DNS server addresses
       
   293 	// (this could be skipped if there was some definite way of knowing
       
   294 	// that nothing has changed since the last collect...)
       
   295 
       
   296 	// Use Delete instead of Reset, so that space is reused? (not freed and reallocated)
       
   297 	iInterfaceList->Delete(0, iInterfaceList->Count());
       
   298 
       
   299 	// Trying to keep "server id" stable, thus do not clear existing
       
   300 	// server list, but just mark entries, so that unused ones can be 
       
   301 	// reclaimed after build is complete.
       
   302 	for (TInt i = iServerList->Count(); --i >= 0; )
       
   303 		iServerList->At(i).iInterface = -2;
       
   304 
       
   305 	LOG(Log::Printf(_L("\t* Scanning interfaces")));
       
   306 	// Read the DNS address from the interface
       
   307 	TSoInetInterfaceInfo *info = new TSoInetInterfaceInfo; // allocate large struct from heap!
       
   308 	if (info && (err = iControl.iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl)) == KErrNone)
       
   309 		{
       
   310 		TPckg<TSoInetInterfaceInfo> opt(*info);
       
   311 		while (iControl.iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
       
   312 			{
       
   313 			if (opt().iName.Length() == 0)
       
   314 				continue;	// "null" interface, ignore
       
   315 			if (!opt().iAddress.IsUnspecified())
       
   316 				{
       
   317 #ifdef _LOG
       
   318 				TBuf<60> tmp;
       
   319 				opt().iAddress.OutputWithScope(tmp);
       
   320 				Log::Printf(_L("\t%S [%S]"), &opt().iName, &tmp);
       
   321 #endif
       
   322 				TInt i = AddToInterfaceList(opt(), iControl.iSocket);
       
   323 				AddToServerList((TInetAddr &)(opt().iNameSer1), i, iControl.iSocket);
       
   324 				AddToServerList((TInetAddr &)(opt().iNameSer2), i, iControl.iSocket);
       
   325 				}
       
   326 			else
       
   327 				{
       
   328 				LOG(Log::Printf(_L("\tInterface: %S [no address, skipping]"), &opt().iName));
       
   329 				}
       
   330 			}
       
   331 		}
       
   332 	delete info;
       
   333 	LOG(Log::Printf(_L("\t* Configured interface specific addresses")));
       
   334 
       
   335 	//
       
   336 	// Add configured servers, if a matching interface has become available
       
   337 	// (assumes that configured list and interface list are always short, so
       
   338 	// the loop over all lists is not too bad...)
       
   339 	if (iConfiguredList)
       
   340 		{
       
   341 		for (TInt i = iConfiguredList->Count(); --i >= 0; )
       
   342 			{
       
   343 			const TDnsConfiguredServer &cs = iConfiguredList->At(i);
       
   344 			for (TInt j = iInterfaceList->Count(); --j >= 0; )
       
   345 				{
       
   346 				const TDnsInterfaceData &data = iInterfaceList->At(j);
       
   347 				if (data.iName.Compare(cs.iName) == 0)
       
   348 					{
       
   349 					// Complete the address with the scope id
       
   350 					// from the interface!
       
   351 					TInetAddr addr(cs.iAddr);
       
   352 					if (addr.Family() == KAfInet)
       
   353 						addr.ConvertToV4Mapped();
       
   354 					const TUint s = addr.Ip6Address().Scope() - 1;
       
   355 					if (s < 16)
       
   356 						{
       
   357 						addr.SetScope(data.iScope[s]);
       
   358 						AddToServerList(addr, j, iControl.iSocket);
       
   359 						}
       
   360 					break;
       
   361 					}
       
   362 				}
       
   363 			}
       
   364 		}
       
   365 	//
       
   366 	// Remove unused servers from the list
       
   367 	//
       
   368 	LOG(Log::Printf(_L("\t* Remove stale addresses")));
       
   369 	const TInt N = iServerList->Count();
       
   370 	TInt k = 0;
       
   371 	for (TInt j = 0; j < N; ++j)
       
   372 		{
       
   373 		const TDnsServerData &a = iServerList->At(j);
       
   374 		if (a.iInterface != -2)
       
   375 			{
       
   376 			// This server entry is still used
       
   377 			if (k != j)
       
   378 				iServerList->At(k) = a;
       
   379 			k++;
       
   380 			}
       
   381 #ifdef _LOG
       
   382 		else
       
   383 			{
       
   384 			TBuf<80> tmp;
       
   385 			a.iAddr.OutputWithScope(tmp);
       
   386 			Log::Printf(_L("\t\tnameserver (id=%d) [%S] deleted"), a.iServerId, &tmp);
       
   387 			}
       
   388 #endif
       
   389 		}
       
   390 	if (k < N)
       
   391 		{
       
   392 		iServerList->Delete(k, N - k);
       
   393 		}
       
   394 
       
   395 	LOG(Log::Printf(_L("CDnsServerManager -- Done, current server count=%d"), iServerList->Count()));
       
   396 	return err;
       
   397 	}
       
   398 
       
   399 // CDnsServerManager::AddServerAddress
       
   400 // ***********************************
       
   401 void CDnsServerManager::AddServerAddress(const TName &aInterface, const TInetAddr &aAddr)
       
   402 	{
       
   403 	if (iConfiguredList == NULL &&
       
   404 		(iConfiguredList = new CArrayFixFlat<TDnsConfiguredServer>(5)) == NULL)
       
   405 		return;		// No memory for the allocation, ignore..
       
   406 
       
   407 	// Do not add duplicates, check existing entries
       
   408 	for (TInt i = iConfiguredList->Count(); --i >= 0; )
       
   409 		{
       
   410 		const TDnsConfiguredServer &cs = iConfiguredList->At(i);
       
   411 		if (cs.iName.Compare(aInterface) == 0 && cs.iAddr.Match(aAddr))
       
   412 			return;	// Duplicate!
       
   413 		}
       
   414 
       
   415 	iConfigure = 1;	// Request rebuild of server list.
       
   416 
       
   417 	TRAP_IGNORE(TDnsConfiguredServer &cf = iConfiguredList->ExtendL();
       
   418 		cf.iAddr = aAddr;
       
   419 		cf.iName = aInterface;
       
   420 		);
       
   421 	}
       
   422 
       
   423 /**
       
   424 // @param	aFilter	the server filter
       
   425 // @parma	aServer	to be tested against the filter
       
   426 // @returns
       
   427 //	@li	TRUE, if the server matches the filter
       
   428 //	@li	FALSE, if the server does not match the filter
       
   429 */
       
   430 TBool CDnsServerManager::Match(const TDnsServerFilter &aFilter, const TDnsServerData &aServer) const
       
   431 	{
       
   432 	if (aFilter.iServerScope != aServer.iScope)
       
   433 		return FALSE;
       
   434 	if (aFilter.iLockType < KIp6AddrScopeNodeLocal || aFilter.iLockType > KIp6AddrScopeNetwork)
       
   435 		return FALSE;	// actually invalid locking scope level
       
   436 
       
   437 	// If a server address is specified without interface (-1), then this
       
   438 	// server will match any filter (if server scopes are same).
       
   439 	if (aServer.iInterface >= 0)
       
   440 		{
       
   441 		const TDnsInterfaceData &id = iInterfaceList->At(aServer.iInterface);
       
   442 		if (aFilter.iLockId != id.iScope[aFilter.iLockType-1])
       
   443 			return FALSE;	// Not in locked scope
       
   444 		}
       
   445 	return 	TRUE;
       
   446 	}
       
   447 
       
   448 
       
   449 //
       
   450 // MDnsServerManager API
       
   451 //
       
   452 TInt CDnsServerManager::OpenList(const TDnsServerFilter &aFilter, MDnsServerListNotify * /*aNotify*/)
       
   453 	{
       
   454 	if (iConfigure)
       
   455 		{
       
   456 		const TInt err = BuildServerList();
       
   457 		if (err != KErrNone)
       
   458 			return err;
       
   459 		iConfigure = 0;
       
   460 		}
       
   461 	if (iStable)
       
   462 		return KErrNone;
       
   463 
       
   464 	if (iControl.GetConfig().iFlushOnConfig && iCacheFlushed == 0)
       
   465 		{
       
   466 		iCacheFlushed = 1;
       
   467 		TRAP_IGNORE(iControl.HandleCommandL(EDndFlush));
       
   468 		}
       
   469 
       
   470 	TTime stamp;
       
   471 	stamp.UniversalTime();
       
   472 	TTimeIntervalSeconds elapsed;
       
   473 	stamp.SecondsFrom(iMark, elapsed);
       
   474 	if (elapsed.Int() > (TInt)iControl.GetConfig().iSetupTime)
       
   475 		{
       
   476 		iStable = 1;
       
   477 		return KErrNone;
       
   478 		}
       
   479 	if (aFilter.iServerScope == EDnsServerScope_MC_LOCAL)
       
   480 		return KErrNone;		
       
   481 	// We are still within setup time, return "pending" if no servers available
       
   482 	return (Count(aFilter) == 0) ? 1 : KErrNone;
       
   483 	}
       
   484 
       
   485 TInt CDnsServerManager::Count(const TDnsServerFilter &aFilter) const
       
   486 	{
       
   487 	TInt count = 0;
       
   488 	for (TInt i = iServerList->Count(); --i >= 0; )
       
   489 		if (Match(aFilter, iServerList->At(i)))
       
   490 			++count;
       
   491 	return count;
       
   492 	}
       
   493 
       
   494 TInt CDnsServerManager::Next(const TDnsServerFilter &aFilter, TInt aServerId) const
       
   495 	{
       
   496 	const TInt N = iServerList->Count();
       
   497 
       
   498 	TInt wrap = 0;
       
   499 	TInt first_found = 0;
       
   500 	TInt current_found = 0;
       
   501 
       
   502 	if (aServerId == 0)
       
   503 		{
       
   504 		//
       
   505 		// When "current" server is not specified, Next will
       
   506 		// return the first server (specified by iServerId)
       
   507 		//
       
   508 		for (TInt i = 0; i < N; ++i)
       
   509 			{
       
   510 			const TDnsServerData &server = iServerList->At(i);
       
   511 			if (server.iServerId == aFilter.iServerId)
       
   512 				first_found = 1;
       
   513 			if (first_found)
       
   514 				{
       
   515 				if (Match(aFilter, server))
       
   516 					return server.iServerId;
       
   517 				}
       
   518 			else if (wrap == 0 && Match(aFilter, server))
       
   519 				wrap = server.iServerId;
       
   520 			}
       
   521 		//
       
   522 		// iServerId server is not present (or it and none
       
   523 		// of the servers after it do not match). Return
       
   524 		// the first matching server.
       
   525 		return wrap;
       
   526 		}
       
   527 	else
       
   528 		{
       
   529 		//
       
   530 		// When aServerId is given, the Next will return
       
   531 		// the next matching server between (current, first)
       
   532 		// (or fail, if none exists)
       
   533 		for (TInt i = 0; i < N; ++i)
       
   534 			{
       
   535 			const TDnsServerData &server =  iServerList->At(i);
       
   536 			if (current_found)
       
   537 				{
       
   538 				if (server.iServerId == aFilter.iServerId)
       
   539 					return 0;	// Back to first, no Matching server
       
   540 				if (Match(aFilter, server))
       
   541 					return server.iServerId;
       
   542 				}
       
   543 			else
       
   544 				{
       
   545 				if (server.iServerId == aServerId)
       
   546 					// Start looking for the next match
       
   547 					current_found = 1;
       
   548 				if (server.iServerId == aFilter.iServerId)
       
   549 					first_found = 1;
       
   550 				if (first_found == 0 && wrap == 0 && Match(aFilter, server))
       
   551 					wrap = server.iServerId;
       
   552 				}
       
   553 			}
       
   554 		//
       
   555 		// Wrap around wrapping
       
   556 		//
       
   557 		if (current_found && first_found)
       
   558 			return wrap;
       
   559 		}
       
   560 	return 0;	// No matching next server!
       
   561 	}
       
   562 
       
   563 void CDnsServerManager::CloseList(const TDnsServerFilter &/*aFilter*/)
       
   564 	{
       
   565 	}
       
   566 
       
   567 
       
   568 TInt CDnsServerManager::Address(TInt aServerId, TInetAddr &aAddr) const
       
   569 	{
       
   570 	const TInt N = iServerList->Count();
       
   571 	for (TInt i = 0; i < N; ++i)
       
   572 		{
       
   573 		const TDnsServerData &server =  iServerList->At(i);
       
   574 		if (server.iServerId == aServerId)
       
   575 			{
       
   576 			aAddr = server.iAddr;
       
   577 			return KErrNone;
       
   578 			}
       
   579 		}
       
   580 	return KErrNotFound;
       
   581 	}
       
   582 
       
   583 TInt CDnsServerManager::ServerId(const TInetAddr &aAddr) const
       
   584 	{
       
   585 	for (TInt i = iServerList->Count(); --i >= 0; )
       
   586 		{
       
   587 		const TDnsServerData &server = iServerList->At(i);
       
   588 		if (server.iAddr.CmpAddr(aAddr) && server.iAddr.Scope() == aAddr.Scope())
       
   589 			return server.iServerId;
       
   590 		}
       
   591 	return 0;
       
   592 	}
       
   593 
       
   594 TUint32 CDnsServerManager::Scope(TInt aServerId, const TInetAddr &aAddr)
       
   595 	{
       
   596 	const TInt N = iServerList->Count();
       
   597 	for (TInt i = 0; i < N; ++i)
       
   598 		{
       
   599 		const TDnsServerData &server = iServerList->At(i);
       
   600 		if (server.iServerId == aServerId)
       
   601 			{
       
   602 			const TUint i = aAddr.Ip6Address().Scope() - 1;
       
   603 			if (i > 15)
       
   604 				return 0;	// Bad scope level.
       
   605 			const TInt j = server.iInterface < 0 ? FindInterface(server.iAddr) : server.iInterface; 
       
   606 			if (j >= 0)
       
   607 				return (iInterfaceList->At(j)).iScope[i];
       
   608 			}
       
   609 		}
       
   610 	return 0;
       
   611 	}
       
   612 
       
   613 
       
   614 static TUint32 MakeNameSpaceId(TInt aServerScope, const TDnsInterfaceData &aIf)
       
   615 	{
       
   616 	//
       
   617 	// Construct the name space id from the server scope and
       
   618 	// matching scope id.
       
   619 	//
       
   620 	if (aServerScope < 0)
       
   621 		aServerScope = -aServerScope;
       
   622 	aServerScope -= 1;
       
   623 	if (aServerScope >= 0 && aServerScope < 16)
       
   624 		return (aIf.iScope[aServerScope] & ~(0xFu << 28)) | ((aServerScope & 0xFu) << 28);
       
   625 	return 0;
       
   626 	}
       
   627 
       
   628 TUint32 CDnsServerManager::NameSpace(const TDnsServerFilter &aFilter, TInt aServerId) const
       
   629 	{
       
   630 	if (aFilter.iLockType < KIp6AddrScopeNodeLocal || aFilter.iLockType > KIp6AddrScopeNetwork)
       
   631 		return 0;	// actually invalid locking type
       
   632 
       
   633 	if (aServerId)
       
   634 		{
       
   635 		const TInt N = iServerList->Count();
       
   636 		for (TInt i = 0; i < N; ++i)
       
   637 			{
       
   638 			const TDnsServerData &server =  iServerList->At(i);
       
   639 			if (server.iServerId == aServerId)
       
   640 				{
       
   641 				if (server.iInterface < 0)
       
   642 					break;
       
   643 				return MakeNameSpaceId(aFilter.iServerScope, iInterfaceList->At(server.iInterface));
       
   644 				}
       
   645 			}
       
   646 		// Should this fall to generic search if server is not
       
   647 		// found? Or, just return 0?
       
   648 		}
       
   649 
       
   650 	for (TInt i = iInterfaceList->Count(); --i >= 0; )
       
   651 		{
       
   652 		TDnsInterfaceData &id = iInterfaceList->At(i);
       
   653 		if (aFilter.iLockId == id.iScope[aFilter.iLockType-1])
       
   654 			return MakeNameSpaceId(aFilter.iServerScope, id);
       
   655 		}
       
   656 	// Cannot find name space id
       
   657 	return 0;
       
   658 	}
       
   659 
       
   660 void CDnsServerManager::LockByAddress(const TInetAddr &aAddr, TUint32 aNid, TDnsServerFilter &aFilter)
       
   661 	{
       
   662 	aFilter.iLockType = aAddr.Ip6Address().Scope();
       
   663 	aFilter.iLockId = aAddr.Scope();
       
   664 	if (aFilter.iLockId)
       
   665 		return;	// Address specified the scope id, all done.
       
   666 	if (aFilter.iLockType == KIp6AddrScopeNetwork)
       
   667 		{
       
   668 		aFilter.iLockId = aNid;
       
   669 		return;	// If lock scope level is network, we can use aNid as is.
       
   670 		}
       
   671 
       
   672 	// Address does not specify the scope id. Try to pick one
       
   673 	// from known interfaces based on the network id.
       
   674 	for (TInt i = iInterfaceList->Count(); --i >= 0; )
       
   675 		{
       
   676 		TDnsInterfaceData &id = iInterfaceList->At(i);
       
   677 		if (aNid == id.iScope[KIp6AddrScopeNetwork-1])
       
   678 			{
       
   679 			aFilter.iLockId = id.iScope[aFilter.iLockType-1];
       
   680 			break;
       
   681 			}
       
   682 		}
       
   683 	}