|
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 } |