|
1 // Copyright (c) 2008-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 // cadvertizehandler.cpp |
|
15 // |
|
16 // |
|
17 /** |
|
18 @file |
|
19 @internalTechnology |
|
20 */ |
|
21 //System include |
|
22 #include <mdns/ccacheentry.h> |
|
23 |
|
24 //UserInclude |
|
25 #include "cadvertizehandler.h" |
|
26 __FLOG_STMT(_LIT8(KComponent,"MDNSServer");) |
|
27 |
|
28 /* |
|
29 * Two phase constructor |
|
30 * @param aMessagHandler areference to messagehandler object. |
|
31 * @param aAutoResolveEnabled If true sercice name conflict will be handled. |
|
32 * aAutoResolveEnabled is True by default |
|
33 */ |
|
34 CAdvertizeHandler* CAdvertizeHandler::NewL(CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled) |
|
35 { |
|
36 CAdvertizeHandler* self = new (ELeave) CAdvertizeHandler(aMessageHandler,aAutoResolveEnabled); |
|
37 CleanupStack::PushL(self); |
|
38 self->ConstructL(); |
|
39 CleanupStack::Pop(); |
|
40 return self; |
|
41 } |
|
42 |
|
43 /* |
|
44 * Destructor |
|
45 */ |
|
46 CAdvertizeHandler::~CAdvertizeHandler() |
|
47 { |
|
48 __FLOG(_L8("CAdvertizeHandler::~CAdvertizeHandler- Entry")); |
|
49 iData.ResetAndDestroy(); |
|
50 iData.Close(); |
|
51 iName.Close(); |
|
52 iProbeName.Close(); |
|
53 iProbeType.Close(); |
|
54 __FLOG(_L8("CAdvertizeHandler::~CAdvertizeHandler- Exit")); |
|
55 __FLOG_CLOSE; |
|
56 } |
|
57 /* |
|
58 * No incoming packet for this so no need to handle |
|
59 */ |
|
60 void CAdvertizeHandler::HandleIncomingPacketL(CDnsMessage& /*aMessage*/) |
|
61 { |
|
62 __FLOG(_L8("CAdvertizeHandler::HandleIncomingPacketL- Entry")); |
|
63 //Nothing To Do ............ |
|
64 __FLOG(_L8("CAdvertizeHandler::HandleIncomingPacketL- Exit")); |
|
65 } |
|
66 |
|
67 static void CleanUpCache(TAny* aAny) |
|
68 { |
|
69 |
|
70 //RPointerArray <CCacheEntry> records = static_cast < RPointerArray <CCacheEntry> > (*aAny); |
|
71 RPointerArray <CCacheEntry>* records = static_cast < RPointerArray <CCacheEntry> *> (aAny); |
|
72 records->ResetAndDestroy(); |
|
73 records->Close(); |
|
74 } |
|
75 /* |
|
76 * Constructor |
|
77 * @param aMessageHandler reference to messagehandler |
|
78 * @param aAutoResolveEnabled will be true by default ,if true servicename conflict |
|
79 * will be handled by default |
|
80 */ |
|
81 CAdvertizeHandler::CAdvertizeHandler(CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled):CBaseHandler(aMessageHandler) |
|
82 { |
|
83 __FLOG(_L8("CAdvertizeHandler::CAdvertizeHandler- Entry")); |
|
84 iAutoResolveEnabled = aAutoResolveEnabled; |
|
85 iCurrentProbeState = EIdle; |
|
86 iProbeCounter = 0 ; |
|
87 __FLOG(_L8("CAdvertizeHandler::CAdvertizeHandler- Exit")); |
|
88 } |
|
89 |
|
90 /* |
|
91 * Twophase constructor |
|
92 */ |
|
93 void CAdvertizeHandler::ConstructL() |
|
94 { |
|
95 __FLOG_OPEN(KMDNSSubsystem, KComponent); |
|
96 __FLOG(_L8("CAdvertizeHandler::ConstructL- Entry")); |
|
97 CBaseHandler::ConstructL(); |
|
98 //Nothing |
|
99 __FLOG(_L8("CAdvertizeHandler::ConstructL- Exit")); |
|
100 } |
|
101 /* |
|
102 * Keeps a copy of the records to be published and starts the active object. |
|
103 * @param aData an array of records to be published. |
|
104 * @param aSessionId session id initiating the advertizement. |
|
105 */ |
|
106 void CAdvertizeHandler::AdvertizePacketL(const RPointerArray<CDnsResourceData> aData, TInt aSessionId,TBool aIsUpdate) |
|
107 { |
|
108 __FLOG(_L8("CAdvertizeHandler::AdvertizePacketL- Entry")); |
|
109 iName.Close(); |
|
110 iName.Create(aData[0]->Name()); |
|
111 iProbeName.Close(); |
|
112 iProbeName.CreateL(KMaxLength); |
|
113 iProbeName.Append(iName); |
|
114 iCurrentProbeState = EStart; |
|
115 iData.ResetAndDestroy(); |
|
116 for(TInt i =0 ; i<aData.Count();i++) |
|
117 { |
|
118 iData.AppendL(aData[i]); |
|
119 } |
|
120 // assign the session id so that, we can send bye-bye packet when the session is closed |
|
121 iSessionId = aSessionId; |
|
122 if(aIsUpdate) |
|
123 { |
|
124 iCurrentProbeState = EIdle; |
|
125 TBool isExist = DefensiveResponseL(); |
|
126 if(!isExist) |
|
127 { |
|
128 User::Leave(KErrNotFound); |
|
129 } |
|
130 SendAnnouncementL(); |
|
131 InsertInCache(); |
|
132 return; |
|
133 } |
|
134 Schedule(); |
|
135 __FLOG(_L8("CAdvertizeHandler::AdvertizePacketL- Exit")); |
|
136 } |
|
137 /* |
|
138 * This is a callback function will be notified whenever a packet sent from this |
|
139 * client is sent to the network. |
|
140 * @param aError any error in sending the packet. |
|
141 */ |
|
142 void CAdvertizeHandler::OnPacketSendL(TInt aError) |
|
143 { |
|
144 __FLOG(_L8("CAdvertizeHandler::OnPacketSendL- Entry")); |
|
145 if(aError != KErrNone) |
|
146 { |
|
147 MessageHandler().NotifyServicePublishL(iName,EFail,iSessionId); |
|
148 } |
|
149 |
|
150 if( iCurrentProbeState != EIdle) |
|
151 { |
|
152 After(KProbeDelay*1000);//Give more delay than this |
|
153 return; |
|
154 } |
|
155 //When a service is published successfully ,iCurrentProbe state will be |
|
156 //EIdle ,this state change will be used to notify the client . |
|
157 MessageHandler().NotifyServicePublishL(iName,ESuccess,iSessionId); |
|
158 __FLOG(_L8("CAdvertizeHandler::OnPacketSendL- Exit")); |
|
159 } |
|
160 |
|
161 void CAdvertizeHandler::RunL() |
|
162 { |
|
163 __FLOG(_L8("CAdvertizeHandler::RunL- Entry")); |
|
164 TTime currentTime; |
|
165 |
|
166 if(iCurrentProbeState <= EProbeComplete) |
|
167 { |
|
168 if(DefensiveResponseL()) |
|
169 { |
|
170 iCurrentProbeState = EStart; |
|
171 if(iAutoResolveEnabled) |
|
172 { |
|
173 GenerateNonConflictingName(); |
|
174 if(iProbeCounter >= KMaxFailures) |
|
175 { |
|
176 //If Probe Failure rate is greater then 15 per second, wait for |
|
177 //5 seconds before probing again |
|
178 iProbeCounter = 0; |
|
179 After(5*1000*1000); |
|
180 } |
|
181 } |
|
182 else // to intimate server of failure |
|
183 { |
|
184 MessageHandler().NotifyServicePublishL(iName,EConflictWithoutAutoResolve,iSessionId); |
|
185 } |
|
186 |
|
187 } |
|
188 } |
|
189 |
|
190 switch(iCurrentProbeState) |
|
191 { |
|
192 case EIdle: |
|
193 break;//Do Nothing |
|
194 |
|
195 case EStart: |
|
196 { |
|
197 currentTime.UniversalTime(); |
|
198 TInt64 randseed = currentTime.Int64(); |
|
199 |
|
200 //Random time between 0 & 250 ms |
|
201 TInt delay = Math::Rand(randseed) % 250; |
|
202 iCurrentProbeState = EProbeFirstUnicast; |
|
203 //Convert to microsecond |
|
204 |
|
205 After(delay*1000); |
|
206 } |
|
207 break; |
|
208 |
|
209 case EProbeFirstUnicast: |
|
210 { |
|
211 SendProbeL(ETrue); |
|
212 iCurrentProbeState = EProbeSecondUnicast; |
|
213 } |
|
214 break; |
|
215 |
|
216 case EProbeSecondUnicast: |
|
217 { |
|
218 SendProbeL(ETrue); |
|
219 iCurrentProbeState = EProbeMulticast; |
|
220 } |
|
221 break; |
|
222 |
|
223 case EProbeMulticast: |
|
224 { |
|
225 SendProbeL(EFalse); |
|
226 iCurrentProbeState = EProbeComplete; |
|
227 } |
|
228 break; |
|
229 |
|
230 case EProbeComplete: |
|
231 { |
|
232 iCurrentProbeState = EFirstAnnouncement; |
|
233 //Probe succeeded ,insert in cache |
|
234 InsertInCache(); |
|
235 After(KProbeDelay*1000); |
|
236 //Some Delay ?? Required or defensive response HAS TO come within 750ms? |
|
237 } |
|
238 break; |
|
239 |
|
240 case EFirstAnnouncement: |
|
241 { |
|
242 SendAnnouncementL(); |
|
243 iCurrentProbeState = ESecondAnnouncement; |
|
244 //After(1000);// A Millisecond delay: Required?? |
|
245 } |
|
246 break; |
|
247 |
|
248 case ESecondAnnouncement: |
|
249 { |
|
250 SendAnnouncementL(); |
|
251 iCurrentProbeState = EIdle; |
|
252 } |
|
253 break; |
|
254 } |
|
255 __FLOG(_L8("CAdvertizeHandler::RunL- Exit")); |
|
256 } |
|
257 /* |
|
258 * Handles any leave in RunL |
|
259 * @param aError error with which runL leaves. |
|
260 */ |
|
261 TInt CAdvertizeHandler::RunError(TInt aError) |
|
262 { |
|
263 __FLOG(_L8("CAdvertizeHandler::RunError- Entry")); |
|
264 return aError; |
|
265 } |
|
266 |
|
267 /* |
|
268 * Self completes the request. |
|
269 */ |
|
270 void CAdvertizeHandler::Schedule() |
|
271 { |
|
272 __FLOG(_L8("CAdvertizeHandler::Schedule- Entry")); |
|
273 TRequestStatus* status(&iStatus); |
|
274 *status = KRequestPending; |
|
275 SetActive(); |
|
276 User::RequestComplete(status, KErrNone); |
|
277 __FLOG(_L8("CAdvertizeHandler::Schedule- Exit")); |
|
278 } |
|
279 |
|
280 /* |
|
281 * Function will be called when there is a conflict. |
|
282 * this will change the publishing name by appending a |
|
283 * number at the end of it. |
|
284 * @return iProbeCounter returns probecounter value. |
|
285 */ |
|
286 TInt CAdvertizeHandler::GenerateNonConflictingName() |
|
287 { |
|
288 __FLOG(_L8("CAdvertizeHandler::GenerateNonConflictingName- Entry")); |
|
289 _LIT8(KDot,"."); |
|
290 |
|
291 RBuf8 oldName; |
|
292 oldName.CreateL(iName); |
|
293 |
|
294 ++iProbeCounter; |
|
295 TBuf8 <KMaxLength> newName; |
|
296 iName.Close(); |
|
297 iName.Create(KMaxLength); |
|
298 iName.Append(iProbeName); |
|
299 |
|
300 TInt pos = iName.Locate('.'); |
|
301 _LIT8(KOpenBrace,"("); |
|
302 newName.Append(KOpenBrace); |
|
303 newName.AppendNum(iProbeCounter); |
|
304 _LIT8(KCloseBrace,")"); |
|
305 newName.Append(KCloseBrace); |
|
306 iName.Insert(pos,newName); |
|
307 ChangeDomainL(oldName); |
|
308 oldName.Close(); |
|
309 __FLOG(_L8("CAdvertizeHandler::GenerateNonConflictingName- Exit")); |
|
310 return iProbeCounter; |
|
311 } |
|
312 |
|
313 /* |
|
314 * Finds whether the service already exists in the network . |
|
315 * If service is in the network ,same will be present in the cache. |
|
316 * @return probFailed returns true if probe has failed. |
|
317 */ |
|
318 TBool CAdvertizeHandler::DefensiveResponseL() |
|
319 { |
|
320 __FLOG(_L8("CAdvertizeHandler::DefensiveResponseL- Entry")); |
|
321 TBool probeFailed(EFalse); |
|
322 RPointerArray <CCacheEntry> entries; |
|
323 CleanupStack::PushL(TCleanupItem(TCleanupOperation(&CleanUpCache),&entries)); |
|
324 |
|
325 _LIT8(KDot,"."); |
|
326 TBuf8 <KMaxLength> buffer; |
|
327 |
|
328 buffer.Copy(iName); |
|
329 buffer.Append(KDot); |
|
330 MessageHandler().DnsCache().FindServiceL(entries,buffer,EDnsQType_Any); |
|
331 if(entries.Count()>0) |
|
332 { |
|
333 probeFailed = ETrue; |
|
334 } |
|
335 CleanupStack::PopAndDestroy(); |
|
336 //entries.ResetAndDestroy(); |
|
337 //entries.Close(); |
|
338 __FLOG(_L8("CAdvertizeHandler::DefensiveResponseL- Exit")); |
|
339 return probeFailed; |
|
340 } |
|
341 |
|
342 /* |
|
343 * creates a DnsMessage object and send it to the messagehandler to handle it. |
|
344 * @param aUnicast true if the packet to be sent is an unicast one;false for multicast. |
|
345 * |
|
346 */ |
|
347 void CAdvertizeHandler::SendProbeL(TBool aUnicast) |
|
348 { |
|
349 __FLOG(_L8("CAdvertizeHandler::SendProbeL- Entry")); |
|
350 //Construct DNS Message |
|
351 CDnsMessage* message = CDnsMessage::NewL(0,ETrue); |
|
352 CleanupStack::PushL(message); |
|
353 |
|
354 //Form the Query/Question part of the message |
|
355 CDnsQuestion* question = CDnsQuestion::NewL(); |
|
356 CleanupStack::PushL(question); |
|
357 question->SetNameL(iName); |
|
358 question->SetClass(EDnsClass_IN); |
|
359 question->SetType(EDnsQType_Any); |
|
360 if(aUnicast) |
|
361 { |
|
362 question->SetUnicast(ETrue); |
|
363 } |
|
364 |
|
365 //Append the Query to the Message |
|
366 message->AppendQueryL(question); |
|
367 //Append to the Authoritative Section |
|
368 for(TInt i =0 ; i < iData.Count();i++) |
|
369 { |
|
370 message->AppendAuthorityL(iData[i]->CloneL()); |
|
371 } |
|
372 |
|
373 //Send the query |
|
374 MessageHandler().SendQueryL(message,*this); |
|
375 |
|
376 CleanupStack::Pop();//question |
|
377 CleanupStack::Pop();//message |
|
378 __FLOG(_L8("CAdvertizeHandler::SendProbeL- Exit")); |
|
379 } |
|
380 |
|
381 /* |
|
382 * If probing is successfull ,new service record will |
|
383 * be added to the cache using this. |
|
384 */ |
|
385 void CAdvertizeHandler::InsertInCache() |
|
386 { |
|
387 __FLOG(_L8("CAdvertizeHandler::InsertInCache- Entry")); |
|
388 TBuf8<KMaxLength> name; |
|
389 _LIT8(KDot,"."); |
|
390 //TODO name should be appended with dot |
|
391 |
|
392 for(TInt i =0 ; i<iData.Count();i++) |
|
393 { |
|
394 //Append a "." at the end of the name |
|
395 name.Copy(iData[i]->Name()); |
|
396 name.Append(KDot); |
|
397 iData[i]->SetNameL(name); |
|
398 MessageHandler().DnsCache().UpdateCacheL(*(iData[i]),ETrue,iSessionId); |
|
399 } |
|
400 __FLOG(_L8("CAdvertizeHandler::InsertInCache- Exit")); |
|
401 } |
|
402 |
|
403 /* |
|
404 * Announces the new service. |
|
405 */ |
|
406 void CAdvertizeHandler::SendAnnouncementL() |
|
407 { |
|
408 __FLOG(_L8("CAdvertizeHandler::SendAnnouncementL- Entry")); |
|
409 RPointerArray<CCacheEntry> entries; |
|
410 //An API in Cache Interface that returns a list of all Authoritative records |
|
411 MessageHandler().DnsCache().AuthoritativeEntriesL(entries); |
|
412 CDnsMessage* message = CDnsMessage::NewL(0,EFalse); |
|
413 CleanupStack::PushL(message); |
|
414 |
|
415 TDnsHeader header(message->Header()); |
|
416 header.SetAuthoritative(ETrue); |
|
417 message->SetHeader(header); |
|
418 |
|
419 //Append to the Authoritative Section |
|
420 for(TInt i =0 ; i < iData.Count();i++) |
|
421 { |
|
422 message->AppendAuthorityL(iData[i]->CloneL()); |
|
423 } |
|
424 |
|
425 /* |
|
426 for(TInt index =0; index<entries.Count();index++) |
|
427 { |
|
428 CCacheEntry* entry = entries[index]; |
|
429 //Send Announcements for all the Services we have published, and entered in Cache |
|
430 |
|
431 |
|
432 if(entry->AddressRecord()) |
|
433 message->AppendAnswerL(entry->AddressRecord()->CloneL()); |
|
434 if(entry->ServiceRecord()) |
|
435 message->AppendAnswerL(entry->ServiceRecord()->CloneL()); |
|
436 if(entry->PtrRecord()) |
|
437 message->AppendAnswerL(entry->PtrRecord()->CloneL()); |
|
438 if(entry->TxtRecord()) |
|
439 message->AppendAnswerL(entry->TxtRecord()->CloneL()); |
|
440 |
|
441 //should've been a new API sendresponse |
|
442 |
|
443 } |
|
444 */ |
|
445 MessageHandler().SendQueryL(message,*this); |
|
446 CleanupStack::Pop();//message |
|
447 entries.ResetAndDestroy(); |
|
448 entries.Close(); |
|
449 __FLOG(_L8("CAdvertizeHandler::SendAnnouncementL- Exit")); |
|
450 } |
|
451 void CAdvertizeHandler::ChangeDomainL(TDesC8& aName) |
|
452 { |
|
453 for(TInt i =0 ; i<iData.Count();i++) |
|
454 { |
|
455 if(iData[i]->Name().Compare(aName) == 0) |
|
456 { |
|
457 iData[i]->SetNameL(iName); |
|
458 } |
|
459 if(iData[i]->Type()==EDnsType_PTR) |
|
460 { |
|
461 CRdTypePtr* ptr = static_cast<CRdTypePtr*>(iData[i]); |
|
462 if(ptr->DomainName().Compare(aName) == 0) |
|
463 { |
|
464 ptr->SetDomainNameL(iName); |
|
465 } |
|
466 |
|
467 } |
|
468 |
|
469 } |
|
470 } |