networkprotocols/tcpipv4v6prt/src/res.cpp
changeset 0 af10295192d8
child 53 7e41d162e158
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // res.cpp - name resolver
       
    15 // This is an implementation of the name service, which is based
       
    16 // on a external resolver application, and translating the queries
       
    17 // into socket read/writes.
       
    18 //
       
    19 
       
    20 
       
    21 
       
    22 /**
       
    23  @file res.cpp
       
    24 */
       
    25 
       
    26 #define SYMBIAN_NETWORKING_UPS
       
    27 
       
    28 #include <in_sock.h>
       
    29 #include "res.h"
       
    30 #include <in_bind.h>	// CProtocolBaseUnbind, MInterfaceManager
       
    31 #include <timeout.h>
       
    32 #include <in6_event.h>
       
    33 #include <in6_opt.h>
       
    34 #include "iface.h"
       
    35 #include "inet6log.h"
       
    36 #include "tcpip_ini.h"
       
    37 #include "networkinfo.h"
       
    38 #include "res_sock.h"
       
    39 #include "inet6err.h"
       
    40 #include <networking/dnd_err.h>
       
    41 
       
    42 #	include <comms-infras/nifif.h>	// Need for TSoIfConnectionInfo
       
    43 #include <es_prot_internal.h>
       
    44 
       
    45 #ifdef SYMBIAN_DNS_PUNYCODE
       
    46 #define ENABLEIDN_SCOPE 0x80
       
    47 #endif //SYMBIAN_DNS_PUNYCODE
       
    48 
       
    49 _LIT_SECURITY_POLICY_C1(KPolicyNetworkControl,  ECapabilityNetworkControl);
       
    50 _LIT_SECURITY_POLICY_C1(KPolicyNetworkServices, ECapabilityNetworkServices);
       
    51 
       
    52 class TDnsRequest : public TDnsRequestBase
       
    53 	/**
       
    54 	* The internal representation of a pending query from application/SocketServer.
       
    55 	*/
       
    56 	{
       
    57 public:
       
    58 	TDnsRequest();
       
    59 	TDnsRequest(const THostName &aName, TDes &aResponse, TInt aType);
       
    60 	TDnsRequest(TNameRecord &aQuery, TInt aNext, TInt aType);
       
    61 	TDnsRequest(const TDesC8 &aQuery, TDes8 &aResponse, TInt aNext);
       
    62 	void BuildMessage(TUint16 aId, TDes8 &aBuffer) const;
       
    63 
       
    64 	TBool IsPending() const { return iQuery.Length() > 0; }
       
    65 
       
    66 	TPtrC8 iQuery;		//< The query buffer
       
    67 	// Reply data
       
    68 	union
       
    69 		{
       
    70 		TUint8 *iResponse;			//< For initializing.
       
    71 		TNameRecord *iNameRecord;	//< GetByAddr/GetByName
       
    72 		TDes8 *iQueryResponse;		//< Query response
       
    73 		TDes *iHostName;			//< GetHostName/SetHostName
       
    74 		};
       
    75 	};
       
    76 
       
    77 // CProtocolRes
       
    78 // ************
       
    79 class CHostResolver;
       
    80 class CProviderRes;
       
    81 class CDndSession;
       
    82 class CProtocolRes : public CProtocolBaseUnbind, public MEventListener
       
    83 	/**
       
    84 	* The "resolver protocol".
       
    85 	*/
       
    86 	{
       
    87 	friend class CProviderRes;
       
    88 	friend class CHostResolver;
       
    89 public:
       
    90 	CProtocolRes(CIfManager &aInterfacer);
       
    91 	virtual ~CProtocolRes();
       
    92 	virtual CServProviderBase *NewSAPL(TUint aProtocol);
       
    93 	virtual CHostResolvProvdBase* NewHostResolverL();
       
    94 	virtual CServiceResolvProvdBase *NewServiceResolverL();
       
    95 	virtual CNetDBProvdBase *NewNetDatabaseL();
       
    96 	virtual void Identify(TServerProtocolDesc *) const;
       
    97 	virtual void BindL(CProtocolBase* protocol, TUint id);
       
    98 	virtual void Unbind(CProtocolBase* protocol, TUint id);
       
    99 	virtual void StartL();
       
   100 	static void FillinInfo(TServerProtocolDesc &anEntry);
       
   101 	//
       
   102 	// Resolver specific Methods
       
   103 	//
       
   104 	inline MInterfaceManager &Interfacer() const { return iInterfacer; }
       
   105 
       
   106 	CHostResolver *FindPending() const;
       
   107 	CProviderRes *NewQuery(CHostResolver *aResolver);
       
   108 private:
       
   109 	void CancelSAP(const CProviderRes &aSAP);		// ..for ~CProviderRes() only!
       
   110 	void CancelQuery(const CHostResolver &aQuery);	// ..for ~CHostResolver() only!
       
   111 	virtual void Notify(TUint aEventClass, TUint aEventType, const void *aData);
       
   112 
       
   113 	CProviderRes *iDND;				//< The Domain Name Resolver Daemon (DND)
       
   114 	CHostResolver *iQueries;		//< List of Queries (RHostResolver sessions)
       
   115 	CIfManager &iInterfacer;		//< The Interface manager link
       
   116 	TUint iConfigureDone:1;			//< = 1, when the Configure request has been sent to DND
       
   117 	};
       
   118 
       
   119 
       
   120 // CProviderRes
       
   121 // ************
       
   122 class CHostResolver;
       
   123 class CDndSession;
       
   124 class CProviderRes: public CServProviderBase
       
   125 	/**
       
   126 	* The "DND provider" (SAP).
       
   127 	*/
       
   128 	{
       
   129 	friend class CProtocolRes;
       
   130 public:
       
   131 	CProviderRes(CProtocolRes &aProtocol);
       
   132 	~CProviderRes();
       
   133 
       
   134 	// 'resolver' has no use for local or remote addresses or ports.
       
   135 	// (these methods should never be called by DND) .None of the Open's are called
       
   136 	// (resolver is always "connectionless datagram socket"). Just silence the
       
   137 	// compiler by defining dummy implementations for all those functions.
       
   138 	virtual void ActiveOpen() {}
       
   139 	virtual void ActiveOpen(const TDesC8 &) {}
       
   140 	virtual TInt PassiveOpen(TUint) { return KErrNone; }
       
   141 	virtual TInt PassiveOpen(TUint ,const TDesC8 &) { return KErrNone; };
       
   142 	virtual void LocalName(TSockAddr &) const {}
       
   143 	virtual TInt SetLocalName(TSockAddr &) { return KErrNone; }
       
   144 	virtual void RemName(TSockAddr &) const {}
       
   145 	virtual TInt SetRemName(TSockAddr &) { return KErrNone; }
       
   146 	virtual void AutoBind() {}
       
   147 
       
   148 	// These are potentially useful, but don't do much currently
       
   149 	virtual void Shutdown(TCloseType option,const TDesC8 &aDisconnectionData);
       
   150 	virtual void Shutdown(TCloseType option);
       
   151 	virtual TInt GetOption(TUint level,TUint name,TDes8 &anOption) const;
       
   152 	virtual void Ioctl(TUint level,TUint name,TDes8* anOption);
       
   153 	virtual void CancelIoctl(TUint aLevel, TUint aName);
       
   154 	virtual TInt SetOption(TUint level,TUint name, const TDesC8 &anOption);
       
   155 
       
   156 	// The real "beef"...
       
   157 	virtual TUint Write(const TDesC8 &aDesc,TUint options, TSockAddr* aAddr=NULL);
       
   158 	virtual void GetData(TDes8 &aDesc,TUint options,TSockAddr *anAddr=NULL);
       
   159 	virtual void Start();
       
   160 	TInt SecurityCheck(MProvdSecurityChecker *aChecker);
       
   161 
       
   162 	// Resolver methods
       
   163 	void Unlink();							//< Called by iResolver to remove the iResolver
       
   164 	void Activate();						//< Used when an attached Session needs servicing.
       
   165 	TBool AssignSession(CHostResolver &aHR);//< Assign a session for the Host Resolver
       
   166 	CProtocolRes &iProtocol;				//< Protocol instance of the 'resolver'
       
   167 protected:
       
   168 	const CDndSession *Find(const TUint16 aId) const;
       
   169 
       
   170 	CDndSession *iSessions;					//< List of associated sessions.
       
   171 	TUint16 iSessionId;						//< Last used session id.
       
   172 	TInt iAvailable;						//< Available sessions in DND.
       
   173 	};
       
   174 	
       
   175 // CDndSession
       
   176 // ***********
       
   177 class CDndSession : public CBase
       
   178 	/**
       
   179 	* The session assigned to the host resolver.
       
   180 	*
       
   181 	* When the DND accepts a host resolver to be served,
       
   182 	* this class is created to represent the session.
       
   183 	*
       
   184 	* Note: This is needed separate from the CHostResolver,
       
   185 	* because
       
   186 	* - the destruction of host resolver is controlled by the socket server,
       
   187 	* - after host resolver has been deleted, the cancel message needs to be delivered to DND
       
   188 	* - when detached from host resolver, this class represents pending session cancel.
       
   189 	*/
       
   190 	{
       
   191 	friend class CProviderRes;
       
   192 public:
       
   193 	void Link(CHostResolver &aHR);		//< Attach Host Resolver to session.
       
   194 	void Unlink();						//< Detach Host Resolver, if any.
       
   195 	void Reply(const TDnsMessage &aReply, const TDesC8 &aPayload) const;
       
   196 	void Submit();
       
   197 	void Answered();
       
   198 	CDndSession *Delete();				//< Trigger destruction of the session.
       
   199 
       
   200 	const TUint16 iSessionId;			//< The session id
       
   201 
       
   202 private:
       
   203 	CDndSession(CProviderRes &aDnd, TUint16 aId, CDndSession *aNext);
       
   204 	~CDndSession();						//< Private destructor, delete only from Delete()
       
   205 
       
   206 
       
   207 	CProviderRes &iDnd;					//< The provider (DND) associated with this session
       
   208 	CDndSession *iNext;					//< Links sessions under provider together
       
   209 	CHostResolver *iResolver;			//< Non-null, if this session is (still) associated with RHostResolver
       
   210 	TTime iAnswerTime;					//< Time of last good answer (only valid if iAnswered == 1).
       
   211 	TUint iPending:1;					//< = 1, when resolver is pending, and query not yet delivered to DND
       
   212 	TUint iAnswered:1;					//< = 1, if at least ONE good answer has been returned.
       
   213 #ifdef SYMBIAN_DNS_PUNYCODE
       
   214 	TUint iEnableIdn:1;					//< = 1, if support for resolving International Domain Names are enabled
       
   215 #endif //SYMBIAN_DNS_PUNYCODE
       
   216 	};
       
   217 
       
   218 
       
   219 // CHostResolver
       
   220 // *************
       
   221 class CHostResolver : public CHostResolvProvdBase
       
   222 	{
       
   223 	/**
       
   224 	* The host resolver.
       
   225 	*
       
   226 	* This is the representative of the application RHostResolver within
       
   227 	* the TCPIP stack. This is created by the CProtocolRes::NewHostResolverL.
       
   228 	*/
       
   229 public:
       
   230 	CHostResolver(CProtocolRes &aProtocol);
       
   231 	~CHostResolver();
       
   232 	void GetByName(TNameRecord &aName);
       
   233 	void GetByAddress(TNameRecord &aName);
       
   234 	void SetHostName(TDes& aNameBuf);
       
   235 	void GetHostName(TDes& aNameBuf);
       
   236 	void CancelCurrentOperation();
       
   237 	TInt SetOption(TUint level, TUint aName,const TDesC8 &option);
       
   238 
       
   239 	void Unlink();						//< Called by iSession, to remove the iSession link
       
   240 	void Reply(const TDnsMessage &aReply, const TDesC8 &aPayload);	//< Called by iSession, when DND has replied.
       
   241 	void QueryComplete(TInt aResult);	//< Called by iSession, when query completed ??
       
   242 	void Query(const TDesC8& aQuery, TDes8& aResult, TInt aCount);
       
   243 	TInt SecurityCheck(MProvdSecurityChecker *aChecker);
       
   244 	TBool IsPending() { return iRequest.IsPending(); }
       
   245 	void BuildMessage(TUint16 aId, TDes8 &aBuffer) const { iRequest.BuildMessage(aId, aBuffer); }
       
   246 #ifdef SYMBIAN_DNS_PUNYCODE
       
   247 	TBool IsIdnEnabled();
       
   248 #endif //SYMBIAN_DNS_PUNYCODE
       
   249 
       
   250 	CHostResolver *iNext;		//< Next resolver link chain
       
   251 	CDndSession *iSession;		//< Assigned DND session or NULL, if none yet.
       
   252 private:
       
   253 	LOG(TInt Session() {return iSession ? (TInt)iSession->iSessionId : 0;})
       
   254 
       
   255 	void Submit();
       
   256 
       
   257 	CProtocolRes &iProtocol;	//< Link to the 'resolver' protocol instance
       
   258 	TUint32 iNetworkId;			//< The default network ID.
       
   259 	TUint32 iCurrentId;			//< The network ID for the current query
       
   260 	TDnsRequest iRequest;		//< The query being served
       
   261 	THostName iHostName;		//< The hostname (only used for SetHostName)
       
   262 	TUint iNoNext:1;			//< if = 1, next should return Not Found
       
   263 	TUint iHasNetworkServices:1;//< = 1, if client has network services.
       
   264 #ifdef SYMBIAN_DNS_PUNYCODE
       
   265 	TUint iEnableIdn:1;			// if =1 , Idn support is enabled.
       
   266 #endif //SYMBIAN_DNS_PUNYCODE
       
   267 	MProvdSecurityChecker *iSecurityChecker;
       
   268 public:
       
   269 	void NoDndAvailable();
       
   270 	RTimeout iTimeout;
       
   271 	};
       
   272 
       
   273 //	CHostResolverLinkage
       
   274 //	***********************
       
   275 //	Glue to bind timeout callback from the timeout manager. Only used for
       
   276 //	detecting a missing or misbehaving DND.
       
   277 
       
   278 // This ungainly manoevure is forced on us because the offset is not evaluated early enough by GCC3.4 to be
       
   279 // passed as a template parameter
       
   280 #if defined(__X86GCC__) || defined(__GCCE__)
       
   281 #define KHostResolverTimeoutOffset 584
       
   282 __ASSERT_COMPILE(KHostResolverTimeoutOffset == _FOFF(CHostResolver, iTimeout));
       
   283 #else
       
   284 #define KHostResolverTimeoutOffset _FOFF(CHostResolver, iTimeout)
       
   285 #endif
       
   286 
       
   287 class CHostResolverLinkage : public TimeoutLinkage<CHostResolver, KHostResolverTimeoutOffset>
       
   288 	{
       
   289 public:
       
   290 	static void Timeout(RTimeout &aLink, const TTime & /*aNow*/, TAny * /*aPtr*/)
       
   291 		{
       
   292 		Object(aLink)->NoDndAvailable();
       
   293 		}
       
   294 	};
       
   295 
       
   296 //
       
   297 //	RES Class Implementation
       
   298 
       
   299 // RES::Identify
       
   300 // *************
       
   301 void RES::Identify(TServerProtocolDesc &aEntry)
       
   302 	{
       
   303 	_LIT(KResolver, "resolver");
       
   304 
       
   305 	aEntry.iName = KResolver;
       
   306 	aEntry.iAddrFamily = KAfInet;
       
   307 	aEntry.iSockType = KSockDatagram;
       
   308 	aEntry.iProtocol = KProtocolInet6Res;
       
   309 	aEntry.iVersion = TVersion(1, 0, 0);
       
   310 	aEntry.iByteOrder = ELittleEndian;
       
   311 	aEntry.iServiceInfo = KSIConnectionLess | KSIMessageBased | KSIRequiresOwnerInfo;
       
   312 	aEntry.iNamingServices = 0;
       
   313 	aEntry.iSecurity = KSocketNoSecurity;
       
   314 	aEntry.iMessageSize = KSocketMessageSizeNoLimit;
       
   315 	aEntry.iServiceTypeInfo = ESocketSupport;
       
   316 	aEntry.iNumSockets = 1;	// Only 1 DND allowed.
       
   317 	}
       
   318 
       
   319 CProtocolBase *RES::NewL(CIfManager *const aInterfacer)
       
   320 	{
       
   321 	return new (ELeave) CProtocolRes(*aInterfacer);
       
   322 	}
       
   323 
       
   324 // Constructors for the TDnsRequest
       
   325 // ********************************
       
   326 
       
   327 TDnsRequest::TDnsRequest() :
       
   328 	TDnsRequestBase(),
       
   329 	iQuery(TPtrC8(0, 0)),
       
   330 	iResponse(NULL)
       
   331 	/**
       
   332 	* Construct empty request = No Query Active
       
   333 	*/
       
   334 	{
       
   335 	}
       
   336 
       
   337 TDnsRequest::TDnsRequest(TNameRecord &aQuery, TInt aNext, TInt aType) :
       
   338 	TDnsRequestBase(aType, aNext),
       
   339 	iQuery(TPtrC8((TUint8 *)&aQuery, sizeof(aQuery))),
       
   340 	iResponse((TUint8 *)&aQuery)
       
   341 	/**
       
   342 	* Construct a GetByName/GetByAddress request.
       
   343 	*
       
   344 	* @param aQuery	The query buffer in the SocketServer
       
   345 	* @param aNext = 0 for the actual query, > 0 for additional results.
       
   346 	* @param aType GetByName or GetByAddress.
       
   347 	*/
       
   348 	{
       
   349 	}
       
   350 
       
   351 TDnsRequest::TDnsRequest(const TDesC8 &aQuery, TDes8 &aResponse, TInt aNext) :
       
   352 	TDnsRequestBase(KDnsRequestType_TDnsQuery, aNext),
       
   353 	iQuery(aQuery),
       
   354 	iResponse((TUint8 *)&aResponse)
       
   355 	/**
       
   356 	* Construct a special DNS query request.
       
   357 	*
       
   358 	* @param aQuery The query buffer in the SocketServer
       
   359 	* @param aResponce The responece buffer in the SocketServer
       
   360 	* @param aNext = 0 for the actual query, > 0 for additional results.
       
   361 	*/
       
   362 	{
       
   363 	}
       
   364 
       
   365 TDnsRequest::TDnsRequest(const THostName &aName, TDes &aResponse, TInt aType) :
       
   366 	TDnsRequestBase(aType, 0),
       
   367 	iQuery(TPtrC8((TUint8 *)&aName, sizeof(aName))),
       
   368 	iResponse((TUint8 *)&aResponse)
       
   369 	/**
       
   370 	* Construct Get/Set HostName.
       
   371 	*
       
   372 	* @param aName The hostname (for SetHostName)
       
   373 	* @param aResponce The responce buffer in the SocketServer
       
   374 	* @param aType Set or get hostname.
       
   375 	*/
       
   376 	{
       
   377 	}
       
   378 
       
   379 void TDnsRequest::BuildMessage(TUint16 aId, TDes8 &aBuffer) const
       
   380 	/**
       
   381 	* Build the message from the request parameters.
       
   382 	*/
       
   383 	{
       
   384 	aBuffer.SetLength(0);
       
   385 	if (aBuffer.MaxLength() >= (TInt)sizeof(TDnsRequestBase) + iQuery.Length())
       
   386 		{
       
   387 		aBuffer = Header();
       
   388 		((TDnsRequestBase *)aBuffer.Ptr())->iSession = aId;
       
   389 		aBuffer.Append(iQuery);
       
   390 		}
       
   391 	else
       
   392 		{
       
   393 		// This means that DND is trying to read with too short buffer.
       
   394 		LOG(Log::Printf(_L("\tres *** DND buffer is short ***")));
       
   395 		}
       
   396 	}
       
   397 
       
   398 //
       
   399 //	CProtocolRes Class Implementation
       
   400 
       
   401 CProtocolRes::CProtocolRes(CIfManager &aInterfacer) : iInterfacer(aInterfacer)
       
   402 	{
       
   403 	LOG(Log::Printf(_L("new\tres resolver[%u] construct"), this));
       
   404 	}
       
   405 
       
   406 void CProtocolRes::BindL(CProtocolBase * /*aProtocol*/, TUint /*aId*/)
       
   407 	/** Dummy. No real functionality. */
       
   408 	{
       
   409 	// Allow anyone to bind, and forget about it...
       
   410 	}
       
   411 
       
   412 void CProtocolRes::Unbind(CProtocolBase * /*aProtocol*/, TUint /*aId*/)
       
   413 	/** Dummy. No real functionality. */
       
   414 	{
       
   415 	// Just pass any unbind too..
       
   416 	}
       
   417 	
       
   418 	
       
   419 // CProtocolRes::StartL
       
   420 // ********************
       
   421 void CProtocolRes::StartL()
       
   422 	{
       
   423 	/**
       
   424 	* Register for the event service.
       
   425 	* Called after all binding is complete. Register for the event
       
   426 	* service to receive configuration changes in the interfaces.
       
   427 	*/
       
   428 	MEventService &mgr = *IMPORT_API_L((&iInterfacer), MEventService);
       
   429 	mgr.RegisterListener(this, EClassAddress);
       
   430 	mgr.RegisterListener(this, EClassInterface);
       
   431 	}
       
   432 
       
   433 // CProtocolRes::Notify
       
   434 // ********************
       
   435 void CProtocolRes::Notify(TUint aEventClass, TUint aEventType, const void *aData)
       
   436 	/**
       
   437 	* Configuration changed event.
       
   438 	*
       
   439 	* This is called by the event manager (MEventService) for the registered events.
       
   440 	* Analyze the event and if the conditions are met, request a "configuration changed"
       
   441 	* message to be sent to the DND.
       
   442 	*
       
   443 	* @param aEventClass The event class
       
   444 	* @param aEventType The event type
       
   445 	* @param aData The event infrormation (TInetAddressInfo or TInetInterfaceInfo)
       
   446 	*/
       
   447 	{
       
   448 	if (!iConfigureDone)
       
   449 		return;	// Configure request is already pending, nothing to do!
       
   450 	
       
   451 	if (aEventClass == EClassAddress)
       
   452 		{
       
   453 		// ...for now, all address events require reconfigure
       
   454 		const TInetAddressInfo &ai = *(TInetAddressInfo *)aData;
       
   455 		if ((ai.iFlags & TInetAddressInfo::EF_Id) == 0)
       
   456 			return;	// Only interested in addresses, not prefixes.
       
   457 		if (aEventType != EventTypeDelete && (ai.iState != TInetAddressInfo::EAssigned))
       
   458 			return;	// Only interested in valid or deleted addresses.
       
   459 #ifdef _LOG
       
   460 		TInetAddr addr(ai.iAddress, 0);
       
   461 		TBuf<70> tmp;
       
   462 		addr.Output(tmp);
       
   463 		Log::Printf(_L("<>\tres Address Event(%d) IF %d [%S]"),  aEventType, ai.iInterface, &tmp);
       
   464 #endif
       
   465 		}
       
   466 	else if (aEventClass == EClassInterface)
       
   467 		{
       
   468 		// ...for now all interface events require reconfigure
       
   469 #ifdef _LOG
       
   470 		const TInetInterfaceInfo &ii = *(TInetInterfaceInfo *)aData;
       
   471 		Log::Printf(_L("<>\tres Interface Event(%d) IF %d [%S]"), aEventType, ii.iIndex, &ii.iName);
       
   472 #endif
       
   473 		}
       
   474 	else
       
   475 		return;
       
   476 	//
       
   477 	// An event that requires DND reconfiguration has occurred.
       
   478 	//
       
   479 	iConfigureDone = 0;
       
   480 	if (iDND)
       
   481 		iDND->Activate();
       
   482 
       
   483 	}
       
   484 
       
   485 // CProtocolRes::NewSAPL
       
   486 // **********************
       
   487 CServProviderBase* CProtocolRes::NewSAPL(TUint /*aSockType*/)
       
   488 	/**
       
   489 	* Create a new DNS SAP.
       
   490 	* This SAP should be the DND server offering the
       
   491 	* name resolution services through this datagram
       
   492 	* socket.
       
   493 	*
       
   494 	* Only ONE DND server at any time can be active. Multiple
       
   495 	* SAP creations are rejected.
       
   496 	*/
       
   497 	{
       
   498 	LOG(Log::Printf(_L("NewSAPL\tres resolver[%u]"), this));
       
   499 	if (iDND)
       
   500 		User::Leave(KErrAlreadyExists); // Only one DND is allowed (should not get here)
       
   501 	iDND = new (ELeave) CProviderRes(*this);
       
   502 	LOG(Log::Printf(_L("\tres DND[%u] new"), iDND));
       
   503 	return iDND;
       
   504 	}
       
   505 
       
   506 // CProtocolRes::NewHostResolverL
       
   507 // ******************************
       
   508 CHostResolvProvdBase *CProtocolRes::NewHostResolverL()
       
   509 	/**
       
   510 	* Create a resolver object.
       
   511 	*
       
   512 	* Create the internal object match the client RHostResolver. These
       
   513 	* objects are stored in the linked list (iQueries) at CProtocolRes.
       
   514 	*
       
   515 	* @return The host resolver
       
   516 	*/
       
   517 	{
       
   518 	CHostResolver *hr = new (ELeave) CHostResolver(*this);
       
   519 	hr->iNext = iQueries;
       
   520 	iQueries = hr;
       
   521 	return hr;
       
   522 	}
       
   523 
       
   524 
       
   525 // CProtocolRes::NewServiceResolverL
       
   526 // *********************************
       
   527 CServiceResolvProvdBase *CProtocolRes::NewServiceResolverL()
       
   528 	/**
       
   529 	* NewServiceResolverL is not supported.
       
   530 	* (Override the default Panic implementation with KErrNotSupported Leave!)
       
   531 	*/
       
   532 	{
       
   533 	User::Leave(KErrNotSupported);
       
   534 	// NOTREACHED
       
   535 	return NULL;
       
   536 	}
       
   537 
       
   538 // CProtocolRes::NewNetDataBaseL
       
   539 // *****************************
       
   540 CNetDBProvdBase *CProtocolRes::NewNetDatabaseL()
       
   541 	/**
       
   542 	* NewNetDatabaseL is not supported.
       
   543 	* (Override the default Panic implementation with KErrNotSupported Leave!)
       
   544 	*/
       
   545 	{
       
   546 	User::Leave(KErrNotSupported);
       
   547 	// NOTREACHED
       
   548 	return NULL;
       
   549 	}
       
   550 
       
   551 // CProtocolRes::CancelSAP
       
   552 // ***********************
       
   553 void CProtocolRes::CancelSAP(const CProviderRes &aSAP)
       
   554 	/**
       
   555 	* The DND has exited.
       
   556 	*
       
   557 	* Only the ~CProviderRes() destructor calls this. This
       
   558 	* removes the reference iDND to the instance.
       
   559 	*/
       
   560 	{
       
   561 	LOG(Log::Printf(_L("\tres DND[%u] terminating"), &aSAP));
       
   562 	if (&aSAP == iDND)
       
   563 		iDND = NULL;
       
   564 	iConfigureDone = 0;	// Clear for the new DND (if any coming).
       
   565 	}
       
   566 
       
   567 // CProtocolRes::CancelQuery
       
   568 // *************************
       
   569 void CProtocolRes::CancelQuery(const CHostResolver &aQuery)
       
   570 	/**
       
   571 	* The host resolver is being deleted.
       
   572 	*
       
   573 	* Only the ~CHostResolver() destructor calls this. This
       
   574 	* removes the reference from the iQueries list.
       
   575 	*/
       
   576 	{
       
   577 	CHostResolver **h, *p;
       
   578 	h = &iQueries;
       
   579 	while ((p = *h) != NULL)
       
   580 		if (p == &aQuery)
       
   581 			{
       
   582 			*h = p->iNext;
       
   583 			return;
       
   584 			}
       
   585 		else
       
   586 			h = &p->iNext;
       
   587 	}
       
   588 
       
   589 // CProtocolRes::FindPending
       
   590 // *************************
       
   591 CHostResolver *CProtocolRes::FindPending() const
       
   592 	/**
       
   593 	* Find a pending request without a session.
       
   594 	*
       
   595 	* Looks through all queries and returns the first one
       
   596 	* which is waiting for a request, but does not yet have
       
   597 	* session object (CDndSession) assigned.
       
   598 	*
       
   599 	* There can be pending requests without session ONLY IF
       
   600 	* DND is not yet running, or if CProviderRes::AssignSession()
       
   601 	* has failed due to all resolver slots being reserved.
       
   602 	* The latter condition should be a rare occurrence
       
   603 	* (should never happen!).
       
   604 	*
       
   605 	* @return The host resolver or NULL if none found.
       
   606 	*/
       
   607 	{
       
   608 	for (CHostResolver *hr = iQueries; hr != NULL; hr = hr->iNext)
       
   609 		if (hr->iSession == NULL && hr->IsPending())
       
   610 			return hr;
       
   611 	return NULL;
       
   612 	}
       
   613 
       
   614 // CProtocolRes::~CProtocolRes
       
   615 // ***************************
       
   616 CProtocolRes::~CProtocolRes()
       
   617 	{
       
   618 	LOG(Log::Printf(_L("\tres resolver[%u] destruct"), this));
       
   619 
       
   620 	ASSERT(iDND == NULL);		// -- cannot get here if there is a DND attached
       
   621 	ASSERT(iQueries == NULL);	// -- cannot get here if there are RHostResolver's
       
   622 
       
   623 	TRAP_IGNORE(MEventService &mgr = *IMPORT_API_L((&iInterfacer), MEventService);
       
   624 		mgr.RemoveListener(this, EClassAddress);
       
   625 		mgr.RemoveListener(this, EClassInterface);
       
   626 		);
       
   627 	}
       
   628 
       
   629 // CProtocolRes::Identify
       
   630 // **********************
       
   631 void CProtocolRes::Identify(TServerProtocolDesc *aInfo) const
       
   632 	{
       
   633 	RES::Identify(*aInfo);
       
   634 	}
       
   635 
       
   636 //
       
   637 // CDndSession
       
   638 
       
   639 CDndSession::CDndSession(CProviderRes &aDnd, TUint16 aSession, CDndSession *aNext)
       
   640 	 : iSessionId(aSession), iDnd(aDnd), iNext(aNext)
       
   641 	{
       
   642 	}
       
   643 	
       
   644 CDndSession::~CDndSession()
       
   645 	{
       
   646 	}
       
   647 
       
   648 // CDndSession::Delete
       
   649 // *******************
       
   650 CDndSession *CDndSession::Delete()
       
   651 	/**
       
   652 	* Delete self.
       
   653 	*
       
   654 	* Deletes self, but returns the link to the
       
   655 	* next session in chain (or NULL, if last).
       
   656 	*
       
   657 	* @return The next in chain.
       
   658 	*/
       
   659 	{
       
   660 	CDndSession *const next = iNext;	// Return iNext field.
       
   661 	
       
   662 	ASSERT(iResolver == NULL);
       
   663 
       
   664 	delete this;
       
   665 	return next;
       
   666 	}
       
   667 
       
   668 // CDndSession::Submit
       
   669 // *******************
       
   670 void CDndSession::Submit()
       
   671 	/**
       
   672 	* Requests a service from DND.
       
   673 	*
       
   674 	* Do the basic details for requesting service for this
       
   675 	* session. Actual nature of the request is not considered
       
   676 	* here (it's up to the caller of this function).
       
   677 	*/
       
   678 	{
       
   679 	iPending = 1;
       
   680 	iAnswered = 0;
       
   681 	iDnd.Activate();	
       
   682 	}
       
   683 
       
   684 // CDndSession::Answered
       
   685 // *********************
       
   686 void CDndSession::Answered()
       
   687 	/**
       
   688 	* Mark session as answered.
       
   689 	*
       
   690 	* The associated host resolver of this session has received
       
   691 	* an answer for the request. This function exists only to
       
   692 	* handle the situation where system does not have enough
       
   693 	* host resolver slots to use. If there is a pending
       
   694 	* request without a session, then this session is
       
   695 	* given to that request. This action makes prevents
       
   696 	* use of the "Next()" action for previous owner of the
       
   697 	* session.
       
   698 	*/
       
   699 	{
       
   700 	CHostResolver *const hr = iDnd.iProtocol.FindPending();
       
   701 	if (hr)
       
   702 		{
       
   703 		// Exceptional branch, reassign session to another.
       
   704 		iResolver->Unlink();
       
   705 		iResolver = NULL;
       
   706 		Link(*hr);
       
   707 		iDnd.Activate();
       
   708 		}
       
   709 	else
       
   710 		{
       
   711 		// Normal branch.
       
   712 		iAnswerTime.UniversalTime();
       
   713 		iAnswered = 1;
       
   714 		}
       
   715 	}
       
   716 
       
   717 // CDndSession::Reply
       
   718 // ******************
       
   719 void CDndSession::Reply(const TDnsMessage &aReply, const TDesC8 &aPayload) const
       
   720 	/**
       
   721 	* A reply from DND.
       
   722 	*
       
   723 	* Relay the reply from DND to the host resolver. If the host resolver
       
   724 	* has already gone away, the reply is simply dropped.
       
   725 	*
       
   726 	* @param aReply The DND reply message (for the header part).
       
   727 	* @param aPayload The DND "payload" part of the reply message.
       
   728 	*/
       
   729 	{
       
   730 	if (iResolver)
       
   731 		iResolver->Reply(aReply, aPayload);
       
   732 	}
       
   733 
       
   734 // CDndSession::Link
       
   735 // *****************
       
   736 void CDndSession::Link(CHostResolver &aHR)
       
   737 	/**
       
   738 	* Link the host resolver to session.
       
   739 	*
       
   740 	* @param aHR The host resolver with query pending
       
   741 	*/
       
   742 	{
       
   743 	ASSERT(aHR.IsPending());
       
   744 	ASSERT(aHR.iSession == NULL);
       
   745 	ASSERT(iResolver == NULL);
       
   746 	aHR.iTimeout.Cancel();
       
   747 	aHR.iSession = this;
       
   748 	iResolver = &aHR;
       
   749 	iPending = 1;
       
   750 #ifdef SYMBIAN_DNS_PUNYCODE
       
   751 	if( aHR.IsIdnEnabled() )
       
   752 	{
       
   753 		iEnableIdn = 1;
       
   754 	}
       
   755 #endif //SYMBIAN_DNS_PUNYCODE
       
   756 	LOG(Log::Printf(_L("\tres HR[%u] SESSION %u assigned HR"), iResolver, (TInt)iSessionId));
       
   757 	}
       
   758 
       
   759 // CDndSession::Unlink()
       
   760 // *********************
       
   761 void CDndSession::Unlink()
       
   762 	/**
       
   763 	* Unlink host resolver from session.
       
   764 	*
       
   765 	* This is called from CHostResolver, when it does not
       
   766 	* need the session any more.
       
   767 	*/
       
   768 	{
       
   769 	ASSERT(iResolver != NULL);	// Should never be called with NULL iResolver!
       
   770 	LOG(Log::Printf(_L("\tres HR[%u] SESSION %u detached HR"), iResolver, (TInt)iSessionId));
       
   771 	iResolver = NULL;
       
   772 	iPending = 0;
       
   773 	// See, if a new resolver should be assigned to this session
       
   774 	CHostResolver *const hr = iDnd.iProtocol.FindPending();
       
   775 	if (hr)
       
   776 		Link(*hr);
       
   777 	// Activate needed always, either to pass a new query or
       
   778 	// cancel, if no new resolver was assigned.
       
   779 	iDnd.Activate();
       
   780 	}
       
   781 
       
   782 //
       
   783 //	CProviderRes Implementation
       
   784 
       
   785 CProviderRes::CProviderRes(CProtocolRes &aProtocol) : iProtocol(aProtocol)
       
   786 	{
       
   787 	}
       
   788 
       
   789 CProviderRes::~CProviderRes()
       
   790 	/**
       
   791 	* DND server has terminated.
       
   792 	* Cleanup all sessions
       
   793 	*/
       
   794 	{
       
   795 	while (iSessions)
       
   796 		iSessions = iSessions->Delete();
       
   797 	iProtocol.CancelSAP(*this);
       
   798 	}
       
   799 
       
   800 
       
   801 // CProviderRes::Activate
       
   802 // **********************
       
   803 void CProviderRes::Activate()
       
   804 	{
       
   805 	/**
       
   806 	* Call socket NewData.
       
   807 	*/
       
   808 	if (iSocket)
       
   809 		iSocket->NewData(1);
       
   810 	}
       
   811 
       
   812 // CProviderRes::Find
       
   813 // ******************
       
   814 const CDndSession *CProviderRes::Find(const TUint16 aId) const
       
   815 	/**
       
   816 	* Find a session by id.
       
   817 	*
       
   818 	* @param aId The session id.
       
   819 	* @return The session or NULL, if not found.
       
   820 	*/
       
   821 	{
       
   822 	const CDndSession *s = iSessions;
       
   823 	for ( ;s != NULL; s = s->iNext)
       
   824 		if (s->iSessionId == aId)
       
   825 			break;
       
   826 	return s;
       
   827 	}
       
   828 
       
   829 //	CProviderRes::Write
       
   830 //	*******************
       
   831 TUint CProviderRes::Write(const TDesC8 &aDesc, TUint /* aResult */, TSockAddr* /*aAddr =NULL*/)
       
   832 	/**
       
   833 	* The reply from DND.
       
   834 	*
       
   835 	* The resolver is now returning some reply. Deliver the reply
       
   836 	* to the matching host resolver (matched by the session id).
       
   837 	*
       
   838 	* @param aDesc The TDnsMessage containing the reply.
       
   839 	* @return Always 1 (= data accepted).
       
   840 	*/
       
   841 	{
       
   842 	const TDnsMessage &reply = *(TDnsMessage *)aDesc.Ptr();
       
   843 	//
       
   844 	// Locate the session for which the reply belongs
       
   845 	//
       
   846 	const CDndSession *const s = Find(reply.iSession);
       
   847 	if (s == NULL)
       
   848 		{
       
   849 		// Ooops! DND is still sending replies to a session that do not
       
   850 		// exist any more. Should there be implicitly generated cancel
       
   851 		// message?
       
   852 		LOG(Log::Printf(_L("Write\tres SESSION %u not found--DND reply ignored"), (TInt)reply.iSession));
       
   853 		}
       
   854 	else
       
   855 		{
       
   856 		const TPtrC8 payload = reply.Payload(aDesc.Length());
       
   857 		s->Reply(reply, payload);
       
   858 		}
       
   859 	return 1;
       
   860 	}
       
   861 	
       
   862 
       
   863 // CProviderRes::AssignSession
       
   864 // ***************************
       
   865 TBool CProviderRes::AssignSession(CHostResolver &aHR)
       
   866 	/**
       
   867 	* Assign a session for a host resolver.
       
   868 	*
       
   869 	* Try to acquire a session for the host resolver.
       
   870 	*
       
   871 	* @param The Host resolver
       
   872 	* @return ETrue, if session assiged, and EFalse otherwise.
       
   873 	*/
       
   874 	{
       
   875 	ASSERT(aHR.IsPending());		// Host resolver must have a query to be done
       
   876 	ASSERT(aHR.iSession == NULL);	// Host resolver must be without a session.
       
   877 
       
   878 	// Check the existing sessions
       
   879 	
       
   880 	CDndSession *a = NULL;
       
   881 	for (CDndSession *s = iSessions; s != NULL; s = s->iNext)
       
   882 		{
       
   883 		if (s->iResolver == NULL)
       
   884 			{
       
   885 			// There is already a session queued for "cancel" request.
       
   886 			// This session can be efficiently reassigned to the new
       
   887 			// host resolver.
       
   888 			s->Link(aHR);
       
   889 			// There is no need to Activate() anything, because there must
       
   890 			// already be a pending Activate() for the cancel message.
       
   891 			return ETrue;
       
   892 			}
       
   893 		else if (s->iAnswered)
       
   894 			{
       
   895 			if (a == NULL || a->iAnswerTime > s->iAnswerTime)
       
   896 				a = s;
       
   897 			}
       
   898 		}
       
   899 
       
   900 	if (iAvailable > 0)
       
   901 		{
       
   902 		// Assign unused session id.
       
   903 		do
       
   904 			{
       
   905 			if (++iSessionId == 0)
       
   906 				iSessionId = 1; // Avoid ZERO as id!
       
   907 			}
       
   908 		while (Find(iSessionId) != NULL);
       
   909 	
       
   910 		a = new CDndSession(*this, iSessionId, iSessions);
       
   911 		if (a)
       
   912 			{
       
   913 			// Created a new session, assign to query.
       
   914 			iAvailable -= 1;
       
   915 			iSessions = a;
       
   916 			a->Link(aHR);
       
   917 			// Activate() is needed, because this is a new session.
       
   918 			Activate();
       
   919 			return ETrue;
       
   920 			}
       
   921 		else
       
   922 			{
       
   923 			aHR.QueryComplete(KErrNoMemory); // <-- check!!!
       
   924 			return EFalse;
       
   925 			}
       
   926 		}
       
   927 
       
   928 	if (a)
       
   929 		{
       
   930 		// Found a session that can be stolen from it's host resolver.
       
   931 		a->iResolver->Unlink();
       
   932 		a->iResolver = NULL;
       
   933 		a->Link(aHR);
       
   934 		// Activate is required
       
   935 		Activate();
       
   936 		return ETrue;
       
   937 		}
       
   938 	// No sessions available
       
   939 	return EFalse;
       
   940 	}
       
   941 
       
   942 // CProviderRes::GetData
       
   943 // *********************
       
   944 void CProviderRes::GetData(TDes8 &aDesc, TUint /* aOptions */, TSockAddr * /*anAddr=NULL*/)
       
   945 	/**
       
   946 	* Prepare the query message for the DND.
       
   947 	*
       
   948 	* Build and return the query message for the DND. The buffer (aDesc) MUST be long enough
       
   949 	* to receive any query.
       
   950 	*
       
   951 	* @retval aDesc The query message.
       
   952 	*/
       
   953 	{
       
   954 	if (!iProtocol.iConfigureDone)
       
   955 		{
       
   956 		//
       
   957 		// Generate a DNS Configure request
       
   958 		//
       
   959 		iProtocol.iConfigureDone = 1;
       
   960 		aDesc.SetLength(sizeof(TDnsRequestBase));
       
   961 		aDesc.FillZ();
       
   962 		((TDnsRequestBase *)aDesc.Ptr())->iType = KDnsRequestType_Configure;
       
   963 		LOG(Log::Printf(_L("GetData\tres DND Configure msg(%d)"), aDesc.Length()));
       
   964 		return;
       
   965 		}
       
   966 	// Find a session that needs to be serviced, return it. If this was
       
   967 	// a cancelled session, then delete entry.
       
   968 	//
       
   969 	// Note: The search starts always from the beginning of the Sessions list,
       
   970 	// and the first one needing service is served. This is not "fair", but
       
   971 	// it is assumed that in practise DND can accept all requests fast.
       
   972 	CDndSession *s;
       
   973 	for (CDndSession **h = &iSessions; (s = *h) != NULL; h = &s->iNext)
       
   974 		{
       
   975 		if (s->iResolver == NULL)
       
   976 			{
       
   977 			// Build a cancel session message with s->iSession
       
   978 			// (just a header and session id is treated as cancel).
       
   979 			aDesc.SetLength(sizeof(TDnsRequestBase));
       
   980 			aDesc.FillZ();
       
   981 			((TDnsRequestBase *)aDesc.Ptr())->iSession = s->iSessionId;
       
   982 			LOG(Log::Printf(_L("GetData\tres SESSION %u DND Cancel msg(%d)"), (TInt)s->iSessionId, aDesc.Length()));
       
   983 			*h = s->Delete();
       
   984 			iAvailable += 1;
       
   985 			return;
       
   986 			}
       
   987 		else if (s->iPending)
       
   988 			{
       
   989 			ASSERT(s->iResolver->IsPending());	// There must be a pending request!
       
   990 			s->iPending = 0;	// Prevent this same request from being sent again to DND.
       
   991 			s->iResolver->BuildMessage(s->iSessionId, aDesc);
       
   992 			LOG(Log::Printf(_L("GetData\tres HR[%u] SESSION %u DND Query msg(%d)"), s->iResolver, (TInt)s->iSessionId, aDesc.Length()));
       
   993 			return;
       
   994 			}
       
   995 		}
       
   996 
       
   997 	// This path is reached ONLY when session is assigned to a host resolver
       
   998 	// and queued (Activated) for processing, but is cancelled by application
       
   999 	// before the DND gets to process the Activate...
       
  1000 	LOG(Log::Printf(_L("GetData\tres Nothing found, empty DND Query")));
       
  1001 	aDesc.SetLength(0);		// No data, nothing to do.
       
  1002 	}
       
  1003 
       
  1004 
       
  1005 void CProviderRes::Start()
       
  1006 	/** The DND is becoming ready to serve. */
       
  1007 	{
       
  1008 	LOG(Log::Printf(_L("\tres DND[%u] Start"), this));
       
  1009 	// Reconfiguration needed
       
  1010 	if (!iProtocol.iConfigureDone)
       
  1011 		Activate();
       
  1012 	}
       
  1013 
       
  1014 void CProviderRes::Shutdown(TCloseType aOption, const TDesC8& /*aDisconnectionData*/)
       
  1015 	{
       
  1016 	/** The DND is shutting down */
       
  1017 	Shutdown(aOption);
       
  1018 	}
       
  1019 
       
  1020 void CProviderRes::Shutdown(TCloseType aOption)
       
  1021 	/** The DND is shutting down */
       
  1022 	{
       
  1023 	LOG(Log::Printf(_L("Shutdown\res DND[%u] type=%d"), this, (TInt)aOption));
       
  1024     if (aOption != EImmediate)
       
  1025         iSocket->CanClose();
       
  1026 	}
       
  1027 
       
  1028 void CProviderRes::Ioctl(TUint /*aLevel*/, TUint /*aName*/, TDes8* /*aOption*/)
       
  1029 	/** Dummy. No real functionality. */
       
  1030 	{
       
  1031 	LOG(Log::Printf(_L("ioctl\tres DND[%u]"), this));
       
  1032 	}
       
  1033 
       
  1034 
       
  1035 void CProviderRes::CancelIoctl(TUint /*aLevel*/, TUint /*aName*/)
       
  1036 	/** Dummy. No real functionality. */
       
  1037 	{
       
  1038 	LOG(Log::Printf(_L("ioctl\tres DND[%u] Cancel"), this));
       
  1039 	}
       
  1040 
       
  1041 TInt CProviderRes::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption)
       
  1042 	/**
       
  1043 	* SetOption.
       
  1044 	*
       
  1045 	* This implements a resolver gate specific option:
       
  1046 	*
       
  1047 	*	level= #KSolDnd, name= #KSoDndSessions
       
  1048 	*
       
  1049 	* The DND must tell the number of available resolver slots to
       
  1050 	* the resolver gateway code using this SetOption.
       
  1051 	*
       
  1052 	* Other options are passed to the interface manager.
       
  1053 	*/
       
  1054 	{
       
  1055 	if (aLevel == KSolDnd)
       
  1056 		{
       
  1057 		if (aName != KSoDndSessions)
       
  1058 			return KErrNotSupported;
       
  1059 
       
  1060 
       
  1061 		if (aOption.Length() < (TInt)sizeof(TInt))
       
  1062 			return KErrGeneral;
       
  1063 		// note: here it is assumed that the Ptr() is properly
       
  1064 		// aligned, but for debug check it! -- msa)
       
  1065 		ASSERT((((TUint)aOption.Ptr()) & 0x3) == 0);
       
  1066 		iAvailable = *((TInt *)aOption.Ptr());
       
  1067 		// Count current sessions and subtract them from iAvailable
       
  1068 		// (it's ok, even if result is negative!)
       
  1069 		for (CDndSession *s = iSessions; s != NULL; s = s->iNext)
       
  1070 			iAvailable -= 1;
       
  1071 		LOG(Log::Printf(_L("SetOpt\tres DND[%u] Sessions=%d"), this, iAvailable));
       
  1072 		// Activate additional pending sessions, if possible.
       
  1073 		CHostResolver *hr;
       
  1074 		while ((hr = iProtocol.FindPending()) != NULL)
       
  1075 			{
       
  1076 			if (!AssignSession(*hr))
       
  1077 				break;
       
  1078 			}
       
  1079 		return KErrNone;
       
  1080 		}
       
  1081 	LOG(Log::Printf(_L("SetOpt\tres DND[%u] level=%d, name=%d"), this, aLevel, aName));
       
  1082 	return iProtocol.Interfacer().SetOption(aLevel, aName, aOption);
       
  1083 	}
       
  1084 
       
  1085 
       
  1086 TInt CProviderRes::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const
       
  1087 	/**
       
  1088 	* GetOption.
       
  1089 	*
       
  1090 	* There is no local options, the call is passed to the interface manager.
       
  1091 	*/
       
  1092 	{
       
  1093 	LOG(Log::Printf(_L("GetOpt\tres DND[%u] level=%d, name=%d"), this, aLevel, aName));
       
  1094 	return iProtocol.Interfacer().GetOption(aLevel, aName, aOption);
       
  1095 	}
       
  1096 
       
  1097 
       
  1098 // CProviderRes::SecurityCheck
       
  1099 // ***************************
       
  1100 TInt CProviderRes::SecurityCheck(MProvdSecurityChecker *aChecker)
       
  1101 	/**
       
  1102 	* Check security of the DND implementor.
       
  1103 	* This represents a socket for the DND server. Check that the
       
  1104 	* application opening this socket actually has the sufficient
       
  1105 	* capability to be the DND.
       
  1106 	*/
       
  1107 	{
       
  1108 	return aChecker->CheckPolicy(KPolicyNetworkControl, "DND Server");
       
  1109 	}
       
  1110 
       
  1111 //
       
  1112 //	CHostResolver Class Implementation
       
  1113 //
       
  1114 
       
  1115 CHostResolver::CHostResolver(CProtocolRes &aProtocol) : iProtocol(aProtocol), iTimeout(CHostResolverLinkage::Timeout)
       
  1116 	{
       
  1117 	LOG(Log::Printf(_L("new\tres HR[%u]"), this));
       
  1118 	SocketServExt::OpenSession();
       
  1119 	// Any host resolver must count as "user" to prevent system
       
  1120 	// from killing the DND while doing resolving.
       
  1121 	iProtocol.Interfacer().IncUsers();
       
  1122 	}
       
  1123 
       
  1124 
       
  1125 CHostResolver::~CHostResolver()
       
  1126 	{
       
  1127 	// Because CancelCurrentOperation() is virtual, avoid using
       
  1128 	// it in desctructor!
       
  1129 	iTimeout.Cancel();
       
  1130 	iProtocol.CancelQuery(*this);
       
  1131 	if (iSession)
       
  1132 		iSession->Unlink();
       
  1133 	iProtocol.Interfacer().DecUsers();
       
  1134 	LOG(Log::Printf(_L("~\tres HR[%u] deleted"), this));
       
  1135 	SocketServExt::CloseSession();
       
  1136 	}
       
  1137 	
       
  1138 // CHostResolver::NoDndAvailable
       
  1139 // *****************************
       
  1140 void CHostResolver::NoDndAvailable()
       
  1141 	/**
       
  1142 	* The timeout expired.
       
  1143 	* This should only happen when there is no DND running.
       
  1144 	* See CHostResolver::Submit
       
  1145 	*/
       
  1146 	{
       
  1147 	if (iProtocol.iDND == NULL)
       
  1148 		QueryComplete(KErrInetNoDnsResolver);
       
  1149 	}
       
  1150 
       
  1151 //
       
  1152 // CHostResolver::Submit
       
  1153 // *********************
       
  1154 void CHostResolver::Submit()
       
  1155 	/**
       
  1156 	* Submit the request to the DND.
       
  1157 	*
       
  1158 	* If there is no DND yet, set a short timer which calls
       
  1159 	* CHostResolver::NoDndAvailable when it expires. Normally,
       
  1160 	* there is always DND running. Only when the stack is
       
  1161 	* starting there is a short time period when host resolvers
       
  1162 	* can request service while DND is still starting up. Any
       
  1163 	* longer delay indicates that the DND startup has failed
       
  1164 	* and the timeout will expire the requests with a specific
       
  1165 	* error code (#KErrInetNoDnsResolver).
       
  1166 	*/
       
  1167 	{
       
  1168 	//
       
  1169 	// Complete the request with network id
       
  1170 	//
       
  1171 	iRequest.iId = iCurrentId;
       
  1172 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1173 	iRequest.iScope |= EScopeType_NET;
       
  1174 #else
       
  1175 	iRequest.iScope = EScopeType_NET;
       
  1176 #endif //SYMBIAN_DNS_PUNYCODE
       
  1177 
       
  1178 
       
  1179 	if (iSession == NULL)
       
  1180 		{
       
  1181 		if (iProtocol.iDND != NULL)
       
  1182 			(void)iProtocol.iDND->AssignSession(*this);
       
  1183 		else
       
  1184 			{
       
  1185 			// Set short timeout, if DND is not yet running.
       
  1186 			iProtocol.iInterfacer.SetTimer(iTimeout, 10);
       
  1187 			}
       
  1188 		}
       
  1189 	else
       
  1190 		iSession->Submit();
       
  1191 	}
       
  1192 
       
  1193 // CHostResolver::SetOption
       
  1194 // ************************
       
  1195 TInt CHostResolver::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption)
       
  1196 	/**
       
  1197 	* SetOption.
       
  1198 	* Implements the #KSoConnectionInfo for the host resolver instance. Other options
       
  1199 	* are passed to the CProtocolRes.
       
  1200 	*/
       
  1201     {
       
  1202 #ifdef SYMBIAN_NETWORKING_UPS
       
  1203 
       
  1204 	if (aLevel == static_cast<TUint>(KSOLProvider))
       
  1205 		{
       
  1206 		if (aName == static_cast<TUint>(KSoConnectionInfo))
       
  1207 			{
       
  1208 			if (aOption.Length() >= sizeof(TSoIfConnectionInfo))
       
  1209 				{
       
  1210 				const TSoIfConnectionInfo& opt = *reinterpret_cast<const TSoIfConnectionInfo*>(aOption.Ptr());
       
  1211 				iNetworkId = opt.iNetworkId;
       
  1212 				return KErrNone;
       
  1213 				}
       
  1214 			else
       
  1215 				{
       
  1216 				return KErrArgument;
       
  1217 				}
       
  1218 			}
       
  1219 		else
       
  1220 		if (aName == static_cast<TUint>(KSoGetErrorCode))
       
  1221 			{
       
  1222 			// Return a TCP/IP failure code appropriate to the last operation.
       
  1223 			// Kludge - SetOption does not allow for any return value via aOption (being const), so
       
  1224 			// return a positive value representing the error code.
       
  1225 			return (iRequest.iType == KDnsRequestType_GetByAddress) ? -KErrDndAddrNotFound : -KErrDndNameNotFound;
       
  1226 			}
       
  1227       	}
       
  1228 
       
  1229 #else
       
  1230 
       
  1231       if (aLevel == STATIC_CAST(TUint, KSOLProvider) && aName == STATIC_CAST(TUint, KSoConnectionInfo))
       
  1232 		if (STATIC_CAST(TUint, aOption.Length()) >= sizeof(TSoIfConnectionInfo))
       
  1233 			{
       
  1234 			// If the client does not have network services, don't allow setting
       
  1235 			// of the network id (=> limit queries to local host data only!).
       
  1236 			if (!iHasNetworkServices)
       
  1237 				return KErrNone;
       
  1238 			TSoIfConnectionInfo &opt = *(TSoIfConnectionInfo*)aOption.Ptr();
       
  1239 			iNetworkId = opt.iNetworkId;
       
  1240 			return KErrNone;
       
  1241 			}
       
  1242 		else
       
  1243 			return KErrArgument;
       
  1244 
       
  1245 #endif
       
  1246 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1247 	else if (aLevel == KSolInetDns )
       
  1248 		{
       
  1249 		if(aName == static_cast<TUint>(KSoDnsEnableIdn) )
       
  1250 			{
       
  1251 			TPckgC<TBool>* setOptPckg=(TPckgC<TBool>*)(&aOption);
       
  1252 			const TBool& enableIdn=(*setOptPckg)();
       
  1253 
       
  1254 			if(enableIdn)
       
  1255 				{
       
  1256 				iEnableIdn = 1;
       
  1257 				}
       
  1258 			else
       
  1259 				{
       
  1260 				if(iEnableIdn == 1)
       
  1261 					{
       
  1262 					iEnableIdn = 0;
       
  1263 					}
       
  1264 				}
       
  1265 			return KErrNone;
       
  1266 			}
       
  1267 		else
       
  1268 			{
       
  1269 			return KErrArgument;
       
  1270 			}
       
  1271 		}
       
  1272 #endif //SYMBIAN_DNS_PUNYCODE
       
  1273 
       
  1274     return iProtocol.SetOption(aLevel, aName, aOption);
       
  1275     }
       
  1276 
       
  1277 // CHostResolver::Unlink
       
  1278 // ************************
       
  1279 void CHostResolver::Unlink()
       
  1280 	/**
       
  1281 	* Unlink resolver from session.
       
  1282 	* Called from the destructor of the attached
       
  1283 	* session to remove the reference to it. If a
       
  1284 	* query is active at this point, the caller will take
       
  1285 	* care of any necessary QueryComplete notifys *after*
       
  1286 	* this! This only needs to remove the link!
       
  1287 	*/
       
  1288 	{
       
  1289 	LOG(Log::Printf(_L("\tres HR[%u] SESSION %d detached"), this, Session()));
       
  1290 	ASSERT(iSession != NULL);	// Should never get called with iSession == NULL!
       
  1291 	iSession = NULL;
       
  1292 	iNoNext = 1;				// Next() cannot be used if session is disconnected.
       
  1293 	}
       
  1294 
       
  1295 // CHostResolver::QueryComplete
       
  1296 // ****************************
       
  1297 void CHostResolver::QueryComplete(TInt aResult)
       
  1298 	/**
       
  1299 	* Pass query completion to the Socket Server.
       
  1300 	*
       
  1301 	* Called by attached resolver service to notify that query has
       
  1302 	* been completed. A passthrough to the socket server. If the
       
  1303 	* result is KErrNone, the reply content has already been copied
       
  1304 	* to the buffer of the socket server.
       
  1305 	*
       
  1306 	* @param aResult The query result code.
       
  1307 	*/
       
  1308 	{
       
  1309 	if (iRequest.IsPending())
       
  1310 		{
       
  1311 #ifndef SYMBIAN_NETWORKING_UPS
       
  1312 		// The result KErrCompletion indicates that the request could not be resolved
       
  1313 		// without use of name servers. If the client does not have network services
       
  1314 		// capability, just return the appropriate "not found" error status.
       
  1315 		if (!iHasNetworkServices && aResult == KErrCompletion)
       
  1316 			aResult = iRequest.iType == KDnsRequestType_GetByAddress ? KErrDndAddrNotFound : KErrDndNameNotFound;
       
  1317 #endif //SYMBIAN_NETWORKING_UPS
       
  1318 		(void)new (&iRequest) TDnsRequest();
       
  1319 		if (aResult == KErrNone)
       
  1320 			{
       
  1321 			// If session attached, mark it answered
       
  1322 			// (note: this information is only used when
       
  1323 			// system is running out of available sessions)
       
  1324 			if (iSession)
       
  1325 				iSession->Answered();
       
  1326 			}
       
  1327 		else if (aResult != KErrCompletion)
       
  1328 			// Any error indicates that there cannot be any further use
       
  1329 			// for the socket gateway to the DND, thus tear it down to
       
  1330 			// release resources. However, KErrCompletion is such that
       
  1331 			// a new call will normally follow, so make exception for it.
       
  1332 			CancelCurrentOperation();
       
  1333 		// Note: CancelCurrentOperation (if executed) must be done before
       
  1334 		// the QueryComplete, because QueryComplete may call directly
       
  1335 		// GetByName or GetByAddress (may happen with KErrCompletion)
       
  1336 		LOG(Log::Printf(_L("\tres HR[%u] SESSION %d QueryComplete(%d)"), this, Session(), aResult));
       
  1337 		iNotify->QueryComplete(aResult);
       
  1338 		}
       
  1339 	else
       
  1340 		CancelCurrentOperation();
       
  1341 	}
       
  1342 
       
  1343 // CHostResolver::Reply
       
  1344 // ********************
       
  1345 void CHostResolver::Reply(const TDnsMessage &aReply, const TDesC8 &aPayload)
       
  1346 	/**
       
  1347 	* The reply has become available.
       
  1348 	* The DND has returned a reply to the query. Pass the results back
       
  1349 	* to application/socket server. Called via CDndSession as follows:
       
  1350 	*
       
  1351 	* DND socket send - CProverRes::Write - CDndSession::Reply - this
       
  1352 	*
       
  1353 	* @param aReply The reply message (for header)
       
  1354 	* @param aPayload The actual reply content.
       
  1355 	*/
       
  1356 	{
       
  1357 	TInt result = aReply.iNext;
       
  1358 	if (result == KErrNone)
       
  1359 		{
       
  1360 		if (aReply.iType != iRequest.iType)
       
  1361 			result = KErrGeneral;	// ...reply format does not match the query format!
       
  1362 		else switch (aReply.iType)
       
  1363 			{
       
  1364 		case KDnsRequestType_GetByName:
       
  1365 		case KDnsRequestType_GetByAddress:
       
  1366 			// The payload is the TNameRecord
       
  1367 			*iRequest.iNameRecord = aReply.NameRecord();
       
  1368 #ifdef _LOG
       
  1369 			{
       
  1370 			TBuf<70> tmp;
       
  1371 			TInetAddr::Cast(iRequest.iNameRecord->iAddr).OutputWithScope(tmp);
       
  1372 			Log::Printf(_L("Write\tres HR[%u] SESSION %d DND Reply = %S [%S]"), this, Session(), &iRequest.iNameRecord->iName, &tmp);
       
  1373 			}
       
  1374 #endif
       
  1375 			break;
       
  1376 		case KDnsRequestType_TDnsQuery:
       
  1377 			if (iRequest.iQueryResponse->MaxSize() >= aPayload.Size())
       
  1378 				{
       
  1379 				*iRequest.iQueryResponse = aPayload;
       
  1380 				LOG(Log::Printf(_L("write\tres HR[%u] DND Reply to query, length=%d"),
       
  1381 							this, iRequest.iQueryResponse->Length()));
       
  1382 				}
       
  1383 			else
       
  1384 				result = KErrTooBig;
       
  1385 			break;
       
  1386 		case KDnsRequestType_GetHostName:
       
  1387 			if (iRequest.iHostName->MaxLength() >= aReply.HostName().Length())
       
  1388 				{
       
  1389 				*iRequest.iHostName = aReply.HostName();
       
  1390 				LOG(Log::Printf(_L("Write\tres HR[%u] SESSION %d DND Reply to GetHostName, %S"),
       
  1391 					this, Session(), iRequest.iHostName));
       
  1392 				}
       
  1393 			else
       
  1394 				result = KErrTooBig;
       
  1395 			break;
       
  1396 		case KDnsRequestType_SetHostName: // does not return any data.
       
  1397 			LOG(Log::Printf(_L("Write\tres HR[%u] SESSION %d DND Reply to SetHostName"), this, Session()));
       
  1398 			break;
       
  1399 		default:
       
  1400 			break;
       
  1401 			}
       
  1402 		}
       
  1403 	else
       
  1404 		LOG(Log::Printf(_L("Write\tres HR[%u] SESSION %d DND Reply Error=%d"), this, Session(), result));
       
  1405 		
       
  1406 	QueryComplete(result);
       
  1407 	}
       
  1408 
       
  1409 // CHostResolver::CancelCurrentOperation
       
  1410 // *************************************
       
  1411 void CHostResolver::CancelCurrentOperation()
       
  1412 	/**
       
  1413 	* Release all extra resources assigned for the host resolver.
       
  1414 	*
       
  1415 	* This function is called when the host resolver does not need
       
  1416 	* any additional resources. Currently this means the release of
       
  1417 	* of the session with DND. The host resolver does not need the
       
  1418 	* session when
       
  1419 	*
       
  1420 	* - current query ends with an error (no additional info is available with session)
       
  1421 	* - the current request is being cancelled
       
  1422 	* - the host resolver is going to be deleted
       
  1423 	*/
       
  1424 	{
       
  1425 	LOG(Log::Printf(_L("\tres HR[%u] SESSION %d CancelCurrentOperation"), this, Session()));
       
  1426 
       
  1427 	(void)new (&iRequest) TDnsRequest();
       
  1428 	if (iSession)
       
  1429 		{
       
  1430 		iSession->Unlink();
       
  1431 		iSession = NULL;
       
  1432 		}
       
  1433 	}
       
  1434 
       
  1435 // CHostResolver::GetHostName
       
  1436 // **************************
       
  1437 void CHostResolver::GetHostName(TDes &aNameBuf)
       
  1438 	/**
       
  1439 	* GetHostName handler.
       
  1440 	* This implements the RHostResolver::GetHostName from the application.
       
  1441 	*/
       
  1442 	{
       
  1443 	iHostName.SetLength(0);
       
  1444 	(void)new (&iRequest) TDnsRequest(iHostName, aNameBuf, KDnsRequestType_GetHostName);
       
  1445 	iCurrentId = iNetworkId;
       
  1446 	LOG(Log::Printf(_L("<>\tres HR[%u] SESSION %d GetHostName(maxlen=%d) NID=%d"),
       
  1447 		 this, Session(), aNameBuf.MaxLength(), iNetworkId));
       
  1448 	Submit();
       
  1449 	}
       
  1450 
       
  1451 // CHostResolver::SetHostName
       
  1452 // **************************
       
  1453 void CHostResolver::SetHostName(TDes& aNameBuf)
       
  1454 	/**
       
  1455 	* SetHostName handler.
       
  1456 	* This implements the RHostResolver::SetHostName from the application.
       
  1457 	*/
       
  1458 	{
       
  1459 	TInt result;
       
  1460 	for (;;)	// ...NOT A LOOP, JUST FOR BREAK EXITS!
       
  1461 		{
       
  1462 		result = iSecurityChecker->CheckPolicy(KPolicyNetworkControl, "SetHostName");
       
  1463 		if (result != KErrNone)
       
  1464 			break;	// ...operation not allowed for this user
       
  1465 		if (iHostName.MaxLength() < aNameBuf.Length())
       
  1466 			{
       
  1467 			result = KErrTooBig;
       
  1468 			break;	// ...the name is too long
       
  1469 			}
       
  1470 		iHostName = aNameBuf;
       
  1471 		(void)new (&iRequest) TDnsRequest(iHostName, iHostName, KDnsRequestType_SetHostName);
       
  1472 		iCurrentId = iNetworkId;
       
  1473 		LOG(Log::Printf(_L("<>\tres HR[%u] SESSION %d SetHostName(%S) NID=%d"), this, Session(), &aNameBuf, iNetworkId));
       
  1474 		Submit();
       
  1475 		// SetHostName has been succesfully submitted
       
  1476 		// to the DND, DND issues the completion later.
       
  1477 		return;
       
  1478 		}
       
  1479 	// SetHostName not done!
       
  1480 	LOG(Log::Printf(_L("<>\tres HR[%u] SESSION %d SetHostName(%S) not done: %d"), this, Session(), &aNameBuf, result));
       
  1481 	iNotify->QueryComplete(result);
       
  1482 	}
       
  1483 
       
  1484 // CHostResolver::GetByName
       
  1485 // ************************
       
  1486 void CHostResolver::GetByName(TNameRecord &aName)
       
  1487 	/**
       
  1488 	* GetByName handler.
       
  1489 	* This implements the RHostResolver::GetByName and RHostResolver::Next() (for the name) from the application.
       
  1490 	*
       
  1491 	* @retval aName The result (and the query in aName.iName as input)
       
  1492 	*/
       
  1493 	{
       
  1494 	ASSERT(!IsPending());	// Cannot be in pending state!
       
  1495 	LOG(Log::Printf(_L("ByName\tres HR[%u] SESSION %d Next=%d NID=%d Name=%S"), this, Session(),
       
  1496 		aName.iFlags, iNetworkId, &aName.iName));
       
  1497 	//
       
  1498 	// Note: aName.iFlage > 0 indicate resolver.Next() request
       
  1499 	//
       
  1500 	(void)new (&iRequest) TDnsRequest(aName, aName.iFlags, KDnsRequestType_GetByName);
       
  1501 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1502 	if(this->iEnableIdn)
       
  1503 		{
       
  1504 		iRequest.iScope |=  ENABLEIDN_SCOPE;
       
  1505 		}
       
  1506 #endif //SYMBIAN_DNS_PUNYCODE
       
  1507 
       
  1508 	TInt result = KErrNotFound;
       
  1509 	for (;;)// ** Just to allow easy exits from a block with 'break'
       
  1510 		{
       
  1511 		TInetAddr &addr = TInetAddr::Cast(aName.iAddr);
       
  1512 
       
  1513 		if (aName.iFlags == 0)
       
  1514 			{
       
  1515 			iNoNext = 1;
       
  1516 
       
  1517 			if (addr.Input(aName.iName) == KErrNone)
       
  1518 				{
       
  1519 				// The name was all numeric IPv4 or IPv6 address
       
  1520 				// (possibly with numeric %scope notation), just
       
  1521 				// return the result as is.
       
  1522 				result = KErrNone;
       
  1523 				break;
       
  1524 				}
       
  1525 
       
  1526 			iCurrentId = iNetworkId;
       
  1527 			const TInt i = aName.iName.LocateReverse('%');
       
  1528 			if (i >= 0)
       
  1529 				{
       
  1530 
       
  1531 				// The name is using the "name%interface" notation. Retrieve
       
  1532 				// the network ID based on the interface, and override
       
  1533 				// the default setting.
       
  1534 				const MInterface *const mi = iProtocol.Interfacer().Interface(aName.iName.Right(aName.iName.Length() - i - 1));
       
  1535 				if (mi == NULL)
       
  1536 					break;	// use default return KErrNotFound, if interface
       
  1537 							// cannot be located.
       
  1538 				iCurrentId = mi->Scope(EScopeType_NET);
       
  1539 				// Remove the "%"-part from the name.
       
  1540 				aName.iName.SetLength(i);
       
  1541 				if (addr.Input(aName.iName) == KErrNone)
       
  1542 					{
       
  1543 					// Remaining part was numeric address, fill in the
       
  1544 					// appropriate scope id. Always return IPv6 (KAfInet6)
       
  1545 					// format address.
       
  1546 					if (addr.Family() != KAfInet6)
       
  1547 						addr.ConvertToV4Mapped();
       
  1548 					addr.SetScope(mi->Scope((TScopeType)(addr.Ip6Address().Scope() - 1)));
       
  1549 					result = KErrNone;
       
  1550 					break;
       
  1551 					}
       
  1552 				// ...was "name%interface" notation, which overrides the
       
  1553 				// default network id.
       
  1554 				// Ignore %-notation without network service capability.
       
  1555 				// (maybe too harsh, but easiest to solve the problem: the
       
  1556 				// notation allows initial non-zero id, without the completion
       
  1557 				// phase (KErrCompletion). Thus, "hostname%RealIf" would allow use
       
  1558 				// network for DNS queries without network services capability!)
       
  1559 				//
       
  1560 				// No change for SYMBIAN_NETWORKING_UPS.  This is an undocumented feature which is not
       
  1561 				// worth changing the TCP/IP stack and ESock to get working with UPS.  The
       
  1562 				// user can make use of an explicit RHostResolver to achieve the same effect.
       
  1563 				if (!iHasNetworkServices)
       
  1564 					iCurrentId = 0;
       
  1565 				}
       
  1566 			iNoNext = 0;	// Allow Next Processing
       
  1567 			}
       
  1568 		else if (iNoNext)
       
  1569 			break;	// KErrNotFound
       
  1570 
       
  1571 		Submit();
       
  1572 		return;	// ** NEVER FORGET TO TERMINATE THE 'FAKE' LOOP! **
       
  1573 		}
       
  1574 	QueryComplete(result);
       
  1575 	}
       
  1576 
       
  1577 // CHostResolver::GetByAddress
       
  1578 // ***************************
       
  1579 void CHostResolver::GetByAddress(TNameRecord &aName)
       
  1580 	/**
       
  1581 	* GetByAddr handler.
       
  1582 	* This implements the RHostResolver::GetByAddr and RHostResolver::Next() (for the addr) from the application.
       
  1583 	*
       
  1584 	* @retval aName  The result (and query aName.iAddr as input)
       
  1585 	*/
       
  1586 	{
       
  1587 	ASSERT(!IsPending());	// Cannot be in pending state!
       
  1588 #ifdef _LOG
       
  1589 	TBuf<100> tmp;
       
  1590 	TInetAddr::Cast(aName.iAddr).OutputWithScope(tmp);
       
  1591 	Log::Printf(_L("ByAddr\tres HR[%u] SESSION %d Next=%d NID=%d Addr=%S"),
       
  1592 		this, Session(), aName.iFlags, iNetworkId, &tmp);
       
  1593 #endif
       
  1594 	//
       
  1595 	// Note: aName.iFlage > 0 indicate resolver.Next() request
       
  1596 	//
       
  1597 	(void)new (&iRequest) TDnsRequest(aName, aName.iFlags, KDnsRequestType_GetByAddress);
       
  1598 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1599 	if(this->iEnableIdn)
       
  1600 		{
       
  1601 			iRequest.iScope |= ENABLEIDN_SCOPE ;
       
  1602 		}
       
  1603 #endif //SYMBIAN_DNS_PUNYCODE
       
  1604 
       
  1605 	TInetAddr &addr = TInetAddr::Cast(aName.iAddr);
       
  1606 	if (aName.iFlags == 0)
       
  1607 		{
       
  1608 		iCurrentId = iNetworkId;
       
  1609 		if (addr.Family() != KAfInet6)
       
  1610 			addr.ConvertToV4Mapped();
       
  1611 		addr.SetPort(0);
       
  1612 		if (addr.Scope() == 0)
       
  1613 			{
       
  1614 			// Pick default scope, if none specified.
       
  1615 			addr.SetScope(iProtocol.Interfacer().RemoteScope(addr.Ip6Address(), iNetworkId, EScopeType_NET));
       
  1616 			}
       
  1617 		iNoNext = 0;	// Allow Next Processing
       
  1618 		}
       
  1619 	else if (iNoNext)
       
  1620 		{
       
  1621 		QueryComplete(KErrNotFound);
       
  1622 		return;
       
  1623 		}
       
  1624 	Submit();
       
  1625 	}
       
  1626 
       
  1627 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1628 // CHostResolver::EnableIdn
       
  1629 // ****************
       
  1630 /**
       
  1631 // @param	None	from the start of the message to the start of domain name
       
  1632 // @returns
       
  1633 //	@li	ETrue , if the IDN support is enabled
       
  1634 //	@li	EFalse, if the IDN support is disabled
       
  1635 */
       
  1636 // ************************
       
  1637 TBool CHostResolver::IsIdnEnabled()
       
  1638 /** 
       
  1639  * IDN Support Enabler
       
  1640  * This implements the RHostResolver::EnableIdn from the application.
       
  1641  * 
       
  1642  * @param aEnable Boolean variable
       
  1643  */
       
  1644 	{
       
  1645 	return (iEnableIdn == 1)? ETrue : EFalse;
       
  1646 	}
       
  1647 #endif //SYMBIAN_DNS_PUNYCODE
       
  1648 
       
  1649 // CHostResolver::Query
       
  1650 // ********************
       
  1651 void CHostResolver::Query(const TDesC8& aQuery, TDes8& aResult, TInt aCount)
       
  1652 	/**
       
  1653 	* Query handler.
       
  1654 	* This implements the RHostResolver::Query and RHostResolver::Next() (for the query) from the application.
       
  1655 	*
       
  1656 	* @param aQuery The query
       
  1657 	* @retval aResult The reply buffer
       
  1658 	* @param aCount The next indicator (0 = first query, > 0 = next).
       
  1659 	*/
       
  1660 	{
       
  1661 	ASSERT(!IsPending());	// Cannot be in pending state!
       
  1662 	iCurrentId = iNetworkId;
       
  1663 	if (aQuery.Length() > 0)
       
  1664 		{
       
  1665 		(void)new (&iRequest) TDnsRequest(aQuery, aResult, aCount);
       
  1666 		LOG(Log::Printf(_L("Query\tres HR[%u] SESSION %d Query(%d, %d, %d) NID=%d"),
       
  1667 					this, Session(), aQuery.Length(), aResult.MaxLength(), aCount, iNetworkId));
       
  1668 #ifdef SYMBIAN_DNS_PUNYCODE
       
  1669 	if(this->iEnableIdn)
       
  1670 		{
       
  1671 		iRequest.iScope |= ENABLEIDN_SCOPE ;
       
  1672 		}
       
  1673 #endif //SYMBIAN_DNS_PUNYCODE
       
  1674 		Submit();
       
  1675 		}
       
  1676 	else
       
  1677 		{
       
  1678 		LOG(Log::Printf(_L("Query\tres HR[%u]::BAD QUERY-ZERO LENGTH"), this));
       
  1679 		iNotify->QueryComplete(KErrArgument);
       
  1680 		}
       
  1681 	}
       
  1682 
       
  1683 // CHostResolver::SecurityCheck
       
  1684 // ****************************
       
  1685 TInt CHostResolver::SecurityCheck(MProvdSecurityChecker *aChecker)
       
  1686 	/**
       
  1687 	* Check the security of RHostResolver user.
       
  1688 	* This represents the host resolver of some application. Check if this application
       
  1689 	* has the capability for network services. If it does not have the capability,
       
  1690 	* it can only query information that can be resolved locally (e.g. hosts file).
       
  1691 	*/
       
  1692 	{
       
  1693 	iSecurityChecker = aChecker;
       
  1694 	iHasNetworkServices = aChecker->CheckPolicy(KPolicyNetworkServices, 0) == KErrNone;
       
  1695 	return KErrNone;
       
  1696 	}