|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // dns_sock.h - Domain Name resolver socket |
|
15 // |
|
16 |
|
17 #ifndef __DNS_SOCK_H__ |
|
18 #define __DNS_SOCK_H__ |
|
19 |
|
20 /** |
|
21 @file dns_sock.h |
|
22 Basic class for sending and receiving DNS protocol packets |
|
23 @internalComponent Domain Name Resolver |
|
24 */ |
|
25 |
|
26 |
|
27 #include <e32std.h> |
|
28 class TMsgBuf; |
|
29 class CDnsSocketWriter; |
|
30 class TDnsRequest; |
|
31 |
|
32 |
|
33 class CDnsSocket : public CBase |
|
34 /** |
|
35 Manage sending and receiving of DNS protocol packets on a socket |
|
36 |
|
37 @internalComponent Domain Name Resolver |
|
38 |
|
39 Class contains the basic control mechanisms for reading and |
|
40 writing the socket. A number of send requests (TDnsRequest) can |
|
41 be queued into the "system" and they will be processed one |
|
42 after another as socket becomes available for a new send. |
|
43 At same time, any incoming packets are received and offered |
|
44 for processing. |
|
45 */ |
|
46 { |
|
47 friend class CDnsSocketWriter; |
|
48 protected: |
|
49 CDnsSocket(TUint aMaxDnsMessage = 0); |
|
50 virtual ~CDnsSocket(); |
|
51 void ConstructL(); |
|
52 /** |
|
53 Open and activate the UDP socket for DNS traffic (unless already done). |
|
54 |
|
55 The CDnsSocket has private memory for local address and port, which |
|
56 both are initialized to unspecified. However, if the |
|
57 ActivateSocketL(const TInetAddr &) has been called, then the last |
|
58 such call defines the local address and port for this method also. |
|
59 The aNetworkId parameter is used to pickup the correct RConnection |
|
60 handle when the EXPLICIT_SOCKET_BINDING option and NON_SEAMLESS_ |
|
61 BEARER mobility is enabled. |
|
62 */ |
|
63 void ActivateSocketL(TUint aNetworkId=0); |
|
64 |
|
65 /** |
|
66 Open and activate the UDP socket for DNS traffic (unless already done). |
|
67 |
|
68 @param aBind |
|
69 defines the local port and addres for the socket. Address |
|
70 and port can be unspecified (the default, if nothing is specified). |
|
71 */ |
|
72 void ActivateSocketL(const TInetAddr &aBind); |
|
73 /** |
|
74 Open and activate the TCP listen socket for DNS traffic. |
|
75 |
|
76 @param aBind |
|
77 defines the local port and addres for the socket. Address |
|
78 and port can be unspecified (the default, if nothing is specified). |
|
79 */ |
|
80 void ActivateListenL(const TInetAddr &aBind, TInt aTTL); |
|
81 // Close and deactivate the UDP socket for DNS traffic |
|
82 void DeactivateSocket(TInt aReason = KErrCancel); |
|
83 void SetHoplimit(const TInt aTTL); |
|
84 /** |
|
85 (Re)Queue the request for processing. |
|
86 |
|
87 @param aRequest to be queued |
|
88 @param aId of the request, if >= 0. If < 0, then a new random ID is generated |
|
89 */ |
|
90 void Queue(TDnsRequest &aRequest, const TInt aId = -1); |
|
91 /** |
|
92 (Re)Queue the request for processing. |
|
93 |
|
94 @param aRequest to be queued |
|
95 @param aSocket identifies a specific active socket within the |
|
96 CDnsSocket to be used (see CDnsSocket::Query). |
|
97 @param aId of the request, if >= 0. If < 0, then a new random ID is generated |
|
98 @return |
|
99 @li KErrNone, if queued successfully, |
|
100 @li KErrNotFound, if the socket does not exist (not queued) |
|
101 */ |
|
102 TInt Queue(TDnsRequest &aRequest, const RSocket &aSocket, const TInt aId = -1); |
|
103 /** |
|
104 (Re)Queue the request for processing using connected socket (TCP) |
|
105 |
|
106 @param aRequest to be queued |
|
107 @param aServer The address and port of the DNS server |
|
108 @param aId of the request, if >= 0. If < 0, then a new random ID is generated |
|
109 @param aTTL of the connection (= -1, the default, requests the system default) |
|
110 |
|
111 @return KErrNone, if queued successfully, or error code if failed. |
|
112 */ |
|
113 TInt Queue(TDnsRequest &aRequest, const TInetAddr &aServer, const TInt aId = -1, const TInt aTTL = -1); |
|
114 /** |
|
115 Reque the request for a resend with same ID (if was queued). |
|
116 |
|
117 If the request is not already queued, action defaults to |
|
118 normal Queue(). |
|
119 |
|
120 @param aRequest to be queued |
|
121 */ |
|
122 void ReSend(TDnsRequest &aRequest); |
|
123 |
|
124 /** |
|
125 Received a Query or unmatched Reply packet |
|
126 |
|
127 The Query method must be implemented by the derived class. The |
|
128 Query is called when a DNS protocol message containing a query |
|
129 or a reply which is not accepted by any of the current requests, |
|
130 is received. |
|
131 |
|
132 @param aBuf the received message |
|
133 @param aServer from which the messsage came |
|
134 @parma aSocket |
|
135 identify originating socket. Note that this |
|
136 "const", you cannot do any socket oprartions with |
|
137 this. It is only provided for the special Queue |
|
138 function, which queues a request to a specific |
|
139 socket. |
|
140 */ |
|
141 virtual void Query(const TMsgBuf &aBuf, const TInetAddr &aServer, const RSocket &aSocket) = 0; |
|
142 /** |
|
143 Communication error with a destination |
|
144 |
|
145 The Error method can be implemented by the derived class. The |
|
146 Error is called when DNS socket receives an ICMP error notification |
|
147 when communicating with this target. |
|
148 |
|
149 @param aServer for which the error relates |
|
150 @param the error from the socket |
|
151 */ |
|
152 virtual void Error(const TInetAddr &aServer, TInt aError) { (void)aServer; (void)aError; }; |
|
153 |
|
154 private: |
|
155 TInt AddSecondaryWriter(CDnsSocketWriter *aWriter); |
|
156 void DeleteWriter(CDnsSocketWriter *aWriter, TInt aReason); |
|
157 CDnsSocketWriter *iWriter; //< Primary Socket Reader/Writer |
|
158 protected: |
|
159 const TUint iMaxDnsMessage; //< Max DNS message length. |
|
160 /** |
|
161 Get the primary RSocket |
|
162 |
|
163 @return a reference to primary RSocket (UDP) |
|
164 */ |
|
165 RSocket& Socket(); |
|
166 TBool IsOpened() const; |
|
167 |
|
168 RSocketServ iSS; //< Keep own Socket Server Session |
|
169 RSocket iListener; //< Used for listening incoming TCP connections, if enabled. |
|
170 TUint iConnected:1; //< = 1, if Socket Server Session is connected. |
|
171 TUint iListening:1; //< = 1, if iListener is open |
|
172 |
|
173 private: |
|
174 TUint iNetworkId; //< = network id fetched from the request |
|
175 }; |
|
176 |
|
177 class TDnsRequestLink : public TDblQueLink |
|
178 /** |
|
179 Link field of requests. |
|
180 |
|
181 This object is ONLY used as a member of TDnsRequest to maintain |
|
182 the links when the request is queued for processing. |
|
183 */ |
|
184 { |
|
185 friend class TDnsRequest; |
|
186 friend class CDnsSocketWriter; |
|
187 public: |
|
188 inline TDnsRequestLink() : iWriter(NULL) {} |
|
189 // @return TRUE, if request is currently queued |
|
190 inline TBool IsQueued() const { return iWriter != NULL; } |
|
191 private: |
|
192 // @return The current socket object, or NULL if not queued |
|
193 inline CDnsSocketWriter *Writer() { return iWriter; } |
|
194 /** |
|
195 Set new DNS socket object. |
|
196 @param aWriter The new socket object |
|
197 */ |
|
198 inline void SetWriter(CDnsSocketWriter *aWriter) { iWriter = aWriter; } |
|
199 /** |
|
200 Identifies the queued status and handler for the request. |
|
201 @li == NULL, |
|
202 when the request is not queued. |
|
203 @li != NULL, |
|
204 a pointer to the internal socket handling object, which |
|
205 is currently assigned to handle the request. |
|
206 */ |
|
207 CDnsSocketWriter *iWriter; |
|
208 }; |
|
209 |
|
210 |
|
211 class TDnsRequest |
|
212 /** |
|
213 // The base class for the DNS query request. |
|
214 // |
|
215 // The request is controlled by three CDnsScoket methods: |
|
216 // |
|
217 // @li CDnsSocket::Queue, (re)enter request into CDnsSocket |
|
218 // @li CDnsSocket::ReSend, (re)enter request into CDnsSocket |
|
219 // @li CDnsSocket::Remove, remove request from CDnsSocket |
|
220 // |
|
221 // While request is "active in the system" (inside CDnsSocket), |
|
222 // it's state and progress is reported by the following callbacks: |
|
223 // |
|
224 // @li TDnsRequest::Build, ready to send a packet |
|
225 // @li TDnsRequest::Sent, packet sent |
|
226 // @li TDnsRequest::Reply, possible reply received |
|
227 // @li TDnsRequest::Abort, request aborted |
|
228 // |
|
229 // The main life cycle of a request is as follows: |
|
230 @verbatim |
|
231 .----->. |
|
232 / \ |
|
233 Remove Queue |
|
234 ^ | |
|
235 |___ | |
|
236 ^ \ V |
|
237 | ReSend / |
|
238 | \ / |
|
239 | \ / |
|
240 |< - - - | |
|
241 | wait for send |
|
242 | possible |
|
243 |< - - - |-------> Build() |
|
244 | send packet |
|
245 | to socket |
|
246 | and wait for |
|
247 | completion |
|
248 |< - - - |-------> Sent() |
|
249 | . |
|
250 | . |
|
251 | | |
|
252 | reply matching |
|
253 | the request id |
|
254 | arrives |
|
255 < - - - |-------> Reply() |
|
256 |
|
257 @endverbatim |
|
258 |
|
259 In addition to above, at any point in the lifetime, TDnsRequest::Abort() |
|
260 could be called, if the request cannot be processed. For example, |
|
261 deactivation of the socket will cause Abort call to all requests. |
|
262 |
|
263 At any point, the owner of the request can ReSend, Queue or Remove it |
|
264 from the system, regardless of the current state of the request. If |
|
265 ReSend is called with request that is not already in the system, the |
|
266 Queue action happens instead. Remove does nothing, if request is not |
|
267 in the system. |
|
268 |
|
269 Note that, when a request is queued, it is only a kind of <em>token</em> |
|
270 that is placed into queue to wait for its turn on sending socket. |
|
271 Nothing about the actual packet to be sent needs to be present, until |
|
272 the DnsRequest::Build is called. |
|
273 */ |
|
274 { |
|
275 friend class TRequestQueue; |
|
276 friend class CDnsSocketWriter; |
|
277 public: |
|
278 /** @brief Build the DNS packet for the request into buffer |
|
279 // |
|
280 // Build callback occurs just before the socket is ready to send a message |
|
281 // corresponding this request. This method should build the desired |
|
282 // message into aBuf, determine the actual destination address (aServer) |
|
283 // return TRUE (= 1). The DnsSocket will start a socket send for the |
|
284 // message. TDnsRequest::Sent will be called, when the socket send |
|
285 // operation completes. |
|
286 // |
|
287 // If message cannot be build (or should not be sent), return FALSE (= 0) |
|
288 // |
|
289 // In either case, the request will remain queued in DnsSocket (unless |
|
290 // removed). |
|
291 // |
|
292 // Build CAN call CDnsSocket::Remove, even if it returns TRUE (in which |
|
293 // case the message will be sent, but there will not be any Sent callback). |
|
294 // |
|
295 // @param aSource the dns socket instance owning the request |
|
296 // @retval aBuf the buffer to be initialized (it has already been preinitialized |
|
297 // using the TDndHeader::Init method). Build method can |
|
298 // either ignore this or use it as a base. |
|
299 // @retval aServer must be initialized with the destination address and port |
|
300 // of the message (if return is TRUE). If the request is |
|
301 // using TCP, this is ignored. |
|
302 // @param aRecvLength |
|
303 // the current size of the receive buffer |
|
304 // |
|
305 // @returns |
|
306 // @li TRUE, if message and server has been set, and socket should send the |
|
307 // message out, request is moved into "wait" state. |
|
308 // @li FALSE, if socket should not send any message from this request. This |
|
309 // causes the request to be moved into "wait" state. |
|
310 */ |
|
311 virtual TBool Build(CDnsSocket &aSource, TMsgBuf &aBuf, TInetAddr &aServer, TInt aRecvLength) = 0; |
|
312 /** @brief A packet has been sent to the server |
|
313 // |
|
314 // Sent callback occurs when the "send" of the message completes on the socket. |
|
315 // This is a notification only. The request remains queued (unless removed). |
|
316 // |
|
317 // Sent CAN call CDnsSocket::Remove. |
|
318 // |
|
319 // @param aSource the dns socket instance owning the request |
|
320 */ |
|
321 virtual void Sent(CDnsSocket &aSource) = 0; |
|
322 /** @brief A reply received |
|
323 // |
|
324 // Reply callback occurs when a socket receives a DNS reply message from a |
|
325 // server with an ID matching this request (in wait state). The Reply |
|
326 // method should do some further verifications whether the reply really |
|
327 // is for this request. |
|
328 // If the reply matches this request, the method should process the reply |
|
329 // and return TRUE. |
|
330 // |
|
331 // If the reply does not match this request, the method should return |
|
332 // FALSE, and the DnsSocket will try another request with same id. If |
|
333 // there are no requests that match this ID (or if all of them return |
|
334 // FALSE, the reply message is offered to the CDnsSocket::Query method). |
|
335 // |
|
336 // In either return (TRUE or FALSE), the request will remain in "wait" state |
|
337 // and queued in DnsSocket (unless removed). |
|
338 // |
|
339 // Reply CAN call CDnsSocket::Remove, and still return either |
|
340 // TRUE or FALSE. |
|
341 // |
|
342 // @param aSource the dns socket instance owning the request |
|
343 // @param aBuf the buffer containing the received reply. |
|
344 // @param aServer the from address of the reply message |
|
345 // |
|
346 // @returns |
|
347 // @li TRUE, if the reply belongs to this request and has been |
|
348 // processed, |
|
349 // @li FALSE, if the reply does not belong to this request, and |
|
350 // some other request should be asked. |
|
351 */ |
|
352 virtual TBool Reply(CDnsSocket &aSource, const TMsgBuf &aBuf, const TInetAddr &aServer) = 0; |
|
353 /** @brief Request aborted |
|
354 // |
|
355 // Abort callback occurs when the DNS socket throws out a request |
|
356 // that it has queued. This is NOT called, when the request is |
|
357 // removed explicitly by CDnsSocket::Remove. The normal reason |
|
358 // for Abort is CDnsSocket::DeactivateSocket, if called with |
|
359 // queued requests present. |
|
360 // |
|
361 // There is no reason for Abort to call CDnsSocket::Remove, |
|
362 // because the request has already been effectively removed |
|
363 // before the Abort call. |
|
364 // |
|
365 // @param aSource the dns socket instance owning the request |
|
366 // @param aReason the reason code for the abort |
|
367 */ |
|
368 virtual void Abort(CDnsSocket &aSource, const TInt aReason) = 0; |
|
369 // Return TRUE, if request is queued |
|
370 inline TBool IsQueued() const { return iQueueLink.IsQueued(); } |
|
371 // Cancel request (silently remove from the queue, if any) |
|
372 void Cancel(); |
|
373 // Return ID value |
|
374 TInt Id() const { return iId; } |
|
375 private: |
|
376 TDnsRequestLink iQueueLink; //< Linking requests together |
|
377 TUint16 iId; //< The assigned request ID |
|
378 }; |
|
379 #endif |