|
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 // |
|
15 |
|
16 #include "cupnpsubscribe.h" |
|
17 #include "upnpconstants.h" |
|
18 #include "pnputils.h" |
|
19 #include <e32const.h> |
|
20 |
|
21 CUPnPSubscribe::CUPnPSubscribe(RSubConnection& aSubConnection , RHostResolver& aResolver):iSubConnection(aSubConnection) |
|
22 ,iResolver ( aResolver ) |
|
23 { |
|
24 } |
|
25 |
|
26 CUPnPSubscribe* CUPnPSubscribe::NewL(RSubConnection& aSubConnection , RHostResolver& aResolver) |
|
27 { |
|
28 CUPnPSubscribe* subscribe=new ( ELeave ) CUPnPSubscribe(aSubConnection , aResolver); |
|
29 CleanupStack::PushL( subscribe ); |
|
30 subscribe->ConstructL(); |
|
31 CleanupStack::Pop(); |
|
32 return subscribe; |
|
33 } |
|
34 |
|
35 void CUPnPSubscribe::ConstructL() |
|
36 { |
|
37 iDeltaTimer=CDeltaTimer::NewL(EPriorityLow); |
|
38 } |
|
39 |
|
40 CUPnPSubscribe:: ~CUPnPSubscribe() |
|
41 { |
|
42 iDeltaTimer->Cancel(); |
|
43 delete iDeltaTimer; |
|
44 delete iElementArray; |
|
45 iTimerMappedArray.ResetAndDestroy(); |
|
46 iCallbackArray.ResetAndDestroy(); |
|
47 iMappedUri=NULL; |
|
48 } |
|
49 |
|
50 /* Sends a subscribe request to the service point.It resolves all the uris passed |
|
51 in the parameter bundle to ip addresses if they're passed as domain names and |
|
52 appends them to element array |
|
53 |
|
54 @param aServiceInfo The parameter bundle which contains the uris to be sent |
|
55 describe requests to |
|
56 */ |
|
57 void CUPnPSubscribe::SubmitRequestL(const RPnPParameterBundle& aServiceInfo) |
|
58 { |
|
59 TInt paramIndex=0; |
|
60 |
|
61 RParameterFamily family = const_cast<RPnPParameterBundle&>(aServiceInfo).FindFamily( EUPnPSubscribeRequestParamSet ); |
|
62 |
|
63 // Iteration 1 : Mainly used for resubscribing request. All the entries |
|
64 // corresponding to the uri which've been subscribed for before and are |
|
65 // present in this parameter set are removed |
|
66 |
|
67 CUPnPSubscribeRequestParamSet* paramSet = NULL; |
|
68 TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ; |
|
69 |
|
70 for ( paramIndex = count - 1; paramIndex >= 0; paramIndex-- ) |
|
71 { |
|
72 paramSet = static_cast<CUPnPSubscribeRequestParamSet*> ( family.GetParameterSetAtIndex ( paramIndex, RParameterFamily::ERequested ) ); |
|
73 |
|
74 const TDesC8& uri = paramSet->Uri(); |
|
75 __ASSERT_DEBUG( paramSet->Uri() != KNullDesC8, User::Panic( KUPnPInvalidUserInput, KUPnPErrInvalidInput ) ); |
|
76 __ASSERT_DEBUG( paramSet->Duration() > 0, User::Panic( KUPnPInvalidUserInput, KUPnPErrInvalidInput ) ); |
|
77 |
|
78 for(TInt i=0;i<iTimerMappedArray.Count();i++) |
|
79 { |
|
80 if(iTimerMappedArray[i]->UriExists(uri)) |
|
81 { |
|
82 CTimerMappedUri* timerUri = iTimerMappedArray[i]; |
|
83 iDeltaTimer->Remove(timerUri->GetTimerEntry()); |
|
84 iTimerMappedArray.Remove(i); |
|
85 delete timerUri; |
|
86 break; |
|
87 } |
|
88 } |
|
89 for( TInt i=0;i<iCallbackArray.Count();i++) |
|
90 { |
|
91 if(uri.CompareF(iCallbackArray[i]->GetUri()) == NULL) |
|
92 { |
|
93 CCallbackArgument* callArgument = iCallbackArray[i]; |
|
94 iCallbackArray.Remove(i); |
|
95 delete callArgument; |
|
96 break; |
|
97 } |
|
98 } |
|
99 |
|
100 if( iElementArray && iElementArray->MatchElement(uri)) |
|
101 iElementArray->RemoveElement(uri); |
|
102 |
|
103 } |
|
104 // Initialize the iterator . The uris will be checked for duplication,resolved |
|
105 // and appended |
|
106 TInetAddr address; |
|
107 |
|
108 for ( paramIndex = count - 1; paramIndex >= 0; paramIndex-- ) |
|
109 { |
|
110 paramSet = static_cast<CUPnPSubscribeRequestParamSet*> ( family.GetParameterSetAtIndex ( paramIndex, RParameterFamily::ERequested ) ); |
|
111 const TDesC8& uri = paramSet->Uri(); |
|
112 |
|
113 // Creates a new Element array if one is not already present and |
|
114 // appends the uri to it. If the uri is duplicate then the corresponding param |
|
115 // set is removed |
|
116 if(!iElementArray) |
|
117 { |
|
118 iElementArray = new CUPnPElementArray; |
|
119 User::LeaveIfNull(iElementArray); |
|
120 iElementArray->InsertElementL(aServiceInfo.PnPObserver(), uri); |
|
121 } |
|
122 else |
|
123 { |
|
124 if(!iElementArray->MatchElement(uri)) |
|
125 { |
|
126 iElementArray->InsertElementL(aServiceInfo.PnPObserver(),uri); |
|
127 } |
|
128 else |
|
129 { |
|
130 reinterpret_cast<RUPnPParameterFamily*>(&family)->DeleteParamSetL(paramIndex); |
|
131 continue; |
|
132 } |
|
133 } |
|
134 |
|
135 CUPnPUtils::ResolveHostAddressL ( iResolver, paramSet->Uri(), address ); |
|
136 paramSet->SetRemoteHost ( address ); |
|
137 |
|
138 } |
|
139 /* Finally if all other processing is done successfully do the |
|
140 * set params |
|
141 */ |
|
142 |
|
143 if ( family.CountParameterSets(RParameterFamily::ERequested)>=1) |
|
144 User::LeaveIfError(iSubConnection.SetParameters(aServiceInfo)); |
|
145 |
|
146 |
|
147 } |
|
148 |
|
149 /* On expiry of the CDeltaTimer associated with the requested uri |
|
150 * it removes the corresponding from the element array and notifies the client |
|
151 */ |
|
152 TInt CUPnPSubscribe::OnTimerExpiry(TAny* aPtr) |
|
153 { |
|
154 TInt error = KErrNone; |
|
155 CCallbackArgument* pointerData= static_cast<CCallbackArgument*> (aPtr); |
|
156 CUPnPSubscribe* thisObject= static_cast<CUPnPSubscribe*> (pointerData->GetThisPointer()); |
|
157 CUPnPElementArray* thisElementArray=thisObject->ElementArrayHandle(); |
|
158 RPointerArray<CTimerMappedUri>& timerArray=thisObject->GetTimerArray(); |
|
159 RPointerArray<CCallbackArgument>& argArray = thisObject->GetArgumentArray(); |
|
160 |
|
161 const TDesC8& uri = pointerData->GetUri(); |
|
162 |
|
163 TInt index; |
|
164 for( index=0; index<timerArray.Count(); index++ ) |
|
165 { |
|
166 if(timerArray[index]->UriExists(uri)) |
|
167 { |
|
168 CTimerMappedUri* timerUri = timerArray[index]; |
|
169 timerArray.Remove(index); |
|
170 delete timerUri; |
|
171 index = -1; |
|
172 break; |
|
173 } |
|
174 } |
|
175 __ASSERT_DEBUG( index == -1 ,User::Panic(KUPnPTimerUriNotFound,KUPnPErrTimerError) ); |
|
176 for( index=0; index<argArray.Count(); index++ ) |
|
177 { |
|
178 const TDesC8& testUri = argArray[index]->GetUri(); |
|
179 if(uri.CompareF(argArray[index]->GetUri())==NULL) |
|
180 { |
|
181 argArray.Remove(index); |
|
182 break; |
|
183 } |
|
184 } |
|
185 MPnPObserver* observer = thisElementArray->MatchElement(uri); |
|
186 __ASSERT_DEBUG( observer , User::Invariant()); |
|
187 // Removes the uri from the element Array |
|
188 HBufC8* notifyUri = pointerData->GetUri().Alloc(); |
|
189 __ASSERT_DEBUG( notifyUri , User::Invariant()); |
|
190 |
|
191 // Deletes the CCallbackargument data |
|
192 delete pointerData; |
|
193 |
|
194 // Notifies the client that timer has expired |
|
195 TRAP(error,thisObject->MakeBundleAndNotifyL(observer, notifyUri)); |
|
196 return KErrNone; |
|
197 } |
|
198 |
|
199 /* Passes back the response bundle to the client. A response bundle |
|
200 will contain only one parameter set consequently with a single observer |
|
201 */ |
|
202 void CUPnPSubscribe::NotifyResultsL(TUint32 aFamilyId, RPnPParameterBundleBase& aBundle) |
|
203 { |
|
204 MPnPObserver* observer = NULL; |
|
205 User::LeaveIfNull(iElementArray); |
|
206 |
|
207 CUPnPSubscribeResponseParamSet* subscribeParamSet = NULL; |
|
208 CUPnPNotifyEventParamSet* notifyParamSet = NULL; |
|
209 RParameterFamily family ; |
|
210 switch(aFamilyId) |
|
211 { |
|
212 case EUPnPSubscribeResponseParamSet: |
|
213 { |
|
214 // Response to subscription request |
|
215 family = aBundle.FindFamily(EUPnPSubscribeResponseParamSet); |
|
216 __ASSERT_DEBUG(!family.IsNull (), User::Panic(KUPnPInvalidFamily,KUPnPErrInvalidFamily)); |
|
217 __ASSERT_DEBUG(family.CountParameterSets(RParameterFamily::ERequested) > 0, User::Panic(KUPnPNoParamSet,KUPnPErrNoParamSet)); |
|
218 TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ; |
|
219 for ( TInt paramIndex = count - 1; paramIndex >= 0; paramIndex-- ) |
|
220 { |
|
221 subscribeParamSet = static_cast<CUPnPSubscribeResponseParamSet*> (family.GetParameterSetAtIndex(paramIndex,RParameterFamily::ERequested)); |
|
222 switch(( subscribeParamSet->UPnPEvent() ).iStatus) |
|
223 { |
|
224 case TUPnPEvent::ESuccess: |
|
225 { |
|
226 /* Extract the uri and the expiry time which has been supplied by |
|
227 * the server and create a deltatimer entry using them |
|
228 */ |
|
229 TInt subscribeExpiryTime = subscribeParamSet->GetTimerExpiry(); |
|
230 const TDesC8& uri = subscribeParamSet->Uri(); |
|
231 observer = iElementArray->MatchElement(uri); |
|
232 __ASSERT_DEBUG( observer != NULL, User::Panic(KUPnPResponseUriNotFound,KUPnPErrResponseUriNotFound)); |
|
233 |
|
234 CreateTimerEntryL(uri,subscribeExpiryTime); |
|
235 } |
|
236 break; |
|
237 |
|
238 case TUPnPEvent::EFail: |
|
239 { |
|
240 const TDesC8& uri = subscribeParamSet->Uri(); |
|
241 observer=iElementArray->MatchElement(uri); |
|
242 __ASSERT_DEBUG( observer != NULL, User::Panic(KUPnPResponseUriNotFound,KUPnPErrResponseUriNotFound)); |
|
243 iElementArray->RemoveElement(uri); |
|
244 } |
|
245 break; |
|
246 |
|
247 default: |
|
248 __ASSERT_DEBUG(0, User::Panic(KUPnPInvalidFamily,KUPnPErrInvalidFamily)); |
|
249 } |
|
250 } |
|
251 } |
|
252 break; |
|
253 |
|
254 case EUPnPNotifyEventParamSet: |
|
255 { |
|
256 |
|
257 // Eventing parameter set |
|
258 family = aBundle.FindFamily( EUPnPNotifyEventParamSet ); |
|
259 TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ; |
|
260 notifyParamSet = static_cast<CUPnPNotifyEventParamSet*> ( family.GetParameterSetAtIndex ( count - 1, RParameterFamily::ERequested ) ); |
|
261 observer = iElementArray->MatchElement(notifyParamSet->Uri()); |
|
262 __ASSERT_DEBUG( observer != NULL, User::Panic(KUPnPResponseUriNotFound,KUPnPErrResponseUriNotFound)); |
|
263 } |
|
264 break; |
|
265 default: |
|
266 __ASSERT_DEBUG(0, User::Panic(KUPnPInvalidFamily,KUPnPErrInvalidFamily)); |
|
267 } |
|
268 |
|
269 observer->OnPnPEventL(aBundle) ; |
|
270 } |
|
271 |
|
272 /* Makes a bundle on expiry of the timer and sends it the client application |
|
273 * saying "Subscription has timed out" |
|
274 */ |
|
275 void CUPnPSubscribe::MakeBundleAndNotifyL(MPnPObserver* aObserver, HBufC8* aUri) |
|
276 { |
|
277 RPnPParameterBundleBase pnpBundle ; |
|
278 pnpBundle.Open(); |
|
279 CleanupClosePushL( pnpBundle ); |
|
280 |
|
281 RParameterFamily family = pnpBundle.CreateFamilyL(EUPnPSubscribeResponseParamSet); |
|
282 // Create a new Param set |
|
283 CUPnPSubscribeResponseParamSet* subscribeParamSet = CUPnPSubscribeResponseParamSet::NewL(family ); |
|
284 |
|
285 // Set the values for the event |
|
286 TUPnPEvent event; |
|
287 event.iStatus=TUPnPEvent::ESubscriptionTimeout; |
|
288 event.iErrorCode = KErrTimedOut; |
|
289 |
|
290 // Set the values in the parameter set |
|
291 subscribeParamSet->SetUPnPEvent(event); |
|
292 subscribeParamSet->SetUriL ( *aUri ); |
|
293 subscribeParamSet->SetTimerExpiry(NULL); |
|
294 |
|
295 CleanupStack::Pop( &pnpBundle); |
|
296 delete aUri; |
|
297 aObserver->OnPnPEventL( pnpBundle ) ; |
|
298 } |
|
299 |
|
300 /* CancelDescribe is used to send cancel subscribe requests to the network |
|
301 @param aServiceInfo The bundle which contains the list of uris whose describe |
|
302 request should be cancelled |
|
303 */ |
|
304 void CUPnPSubscribe::CancelSubscribeL( const RPnPParameterBundle& aServiceInfo ) |
|
305 { |
|
306 User::LeaveIfNull(iElementArray); |
|
307 RParameterFamily family = const_cast<RPnPParameterBundle&>(aServiceInfo).FindFamily( EUPnPCancelSubscribeParamSet ); |
|
308 |
|
309 CUPnPCancelSubscribeParamSet* paramSet = NULL; |
|
310 TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ; |
|
311 |
|
312 for ( TInt paramIndex = count - 1; paramIndex >= 0; paramIndex-- ) |
|
313 { |
|
314 paramSet = static_cast<CUPnPCancelSubscribeParamSet*> ( family.GetParameterSetAtIndex ( paramIndex, RParameterFamily::ERequested) ); |
|
315 //Extract the uri |
|
316 const TDesC8& uri = paramSet->Uri(); |
|
317 __ASSERT_DEBUG( paramSet->Uri() != KNullDesC8, User::Panic( KUPnPInvalidUserInput, KUPnPErrInvalidInput ) ); |
|
318 |
|
319 // Removes the uri entry from the array if exists |
|
320 for(TInt i=0;i<iTimerMappedArray.Count();i++) |
|
321 { |
|
322 if(iTimerMappedArray[i]->UriExists(uri) ) |
|
323 { |
|
324 CTimerMappedUri* timerUri = iTimerMappedArray[i]; |
|
325 iDeltaTimer->Remove(timerUri->GetTimerEntry()); |
|
326 iTimerMappedArray.Remove(i); |
|
327 delete timerUri; |
|
328 break; |
|
329 } |
|
330 } |
|
331 for( TInt i=0;i<iCallbackArray.Count();i++) |
|
332 { |
|
333 if(uri.CompareF(iCallbackArray[i]->GetUri()) == NULL) |
|
334 { |
|
335 CCallbackArgument* callArgument = iCallbackArray[i]; |
|
336 iCallbackArray.Remove(i); |
|
337 delete callArgument; |
|
338 break; |
|
339 } |
|
340 } |
|
341 |
|
342 // Remove the entry from element array |
|
343 MPnPObserver* observer = iElementArray->MatchElement( uri ); |
|
344 if ( !observer ) |
|
345 { |
|
346 reinterpret_cast<RUPnPParameterFamily*>(&family)->DeleteParamSetL ( paramIndex ); |
|
347 continue; |
|
348 } |
|
349 iElementArray->RemoveElement( uri ); |
|
350 } |
|
351 if ( family.CountParameterSets(RParameterFamily::ERequested) >= 1) |
|
352 User::LeaveIfError(iSubConnection.SetParameters( aServiceInfo )); |
|
353 |
|
354 } |
|
355 |
|
356 /* The timer delay is adjusted to 90% of the subscription time.Also it is adjusted |
|
357 for microseconds and IPC lag |
|
358 */ |
|
359 TInt CUPnPSubscribe::AdjustedDelay( TInt aTime ) |
|
360 { |
|
361 TUint64 divisor = 10; |
|
362 TUint64 temp; // just a placeholder |
|
363 TUint64 q = Math::UDivMod64(aTime,divisor,temp); |
|
364 temp = q*(divisor-1); |
|
365 aTime = static_cast<TInt>(temp); |
|
366 |
|
367 const TInt KIntTime = 1000000 ; |
|
368 const TInt KInternalIPCLag = 1; |
|
369 aTime = ( aTime + KInternalIPCLag ) * KIntTime ; |
|
370 return aTime; |
|
371 } |
|
372 |
|
373 /* CreateTimerEntry : creates the deltatimer entry and queues it up |
|
374 */ |
|
375 void CUPnPSubscribe::CreateTimerEntryL(const TDesC8& aUri ,TInt aExpiryTime) |
|
376 |
|
377 { |
|
378 CCallbackArgument* callArgument = CCallbackArgument::NewL(this,aUri); |
|
379 CleanupStack::PushL(callArgument); |
|
380 iCallbackArray.AppendL(callArgument); |
|
381 CleanupStack::Pop(); |
|
382 |
|
383 TCallBack callBack(OnTimerExpiry,callArgument); |
|
384 iTimerEntry = new(ELeave) TDeltaTimerEntry( callBack ); |
|
385 iMappedUri = CTimerMappedUri::NewL(aUri, iTimerEntry,aExpiryTime); |
|
386 iTimerMappedArray.AppendL(iMappedUri); |
|
387 |
|
388 // The time is set to 90% of the given time to allow the user |
|
389 // to resubscribe before the expiry time |
|
390 TInt time = AdjustedDelay(aExpiryTime); |
|
391 TTimeIntervalMicroSeconds32 delay(time); |
|
392 iDeltaTimer->Queue(delay,*iTimerEntry); |
|
393 } |
|
394 |
|
395 |