--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servicediscoveryandcontrol/pnp/test/upnp/Client/upnpplugin/src/cupnpsubscribe.cpp Tue Feb 02 01:12:20 2010 +0200
@@ -0,0 +1,395 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "cupnpsubscribe.h"
+#include "upnpconstants.h"
+#include "pnputils.h"
+#include <e32const.h>
+
+CUPnPSubscribe::CUPnPSubscribe(RSubConnection& aSubConnection , RHostResolver& aResolver):iSubConnection(aSubConnection)
+ ,iResolver ( aResolver )
+ {
+ }
+
+CUPnPSubscribe* CUPnPSubscribe::NewL(RSubConnection& aSubConnection , RHostResolver& aResolver)
+ {
+ CUPnPSubscribe* subscribe=new ( ELeave ) CUPnPSubscribe(aSubConnection , aResolver);
+ CleanupStack::PushL( subscribe );
+ subscribe->ConstructL();
+ CleanupStack::Pop();
+ return subscribe;
+ }
+
+void CUPnPSubscribe::ConstructL()
+ {
+ iDeltaTimer=CDeltaTimer::NewL(EPriorityLow);
+ }
+
+CUPnPSubscribe:: ~CUPnPSubscribe()
+ {
+ iDeltaTimer->Cancel();
+ delete iDeltaTimer;
+ delete iElementArray;
+ iTimerMappedArray.ResetAndDestroy();
+ iCallbackArray.ResetAndDestroy();
+ iMappedUri=NULL;
+ }
+
+/* Sends a subscribe request to the service point.It resolves all the uris passed
+ in the parameter bundle to ip addresses if they're passed as domain names and
+ appends them to element array
+
+ @param aServiceInfo The parameter bundle which contains the uris to be sent
+ describe requests to
+ */
+void CUPnPSubscribe::SubmitRequestL(const RPnPParameterBundle& aServiceInfo)
+ {
+ TInt paramIndex=0;
+
+ RParameterFamily family = const_cast<RPnPParameterBundle&>(aServiceInfo).FindFamily( EUPnPSubscribeRequestParamSet );
+
+ // Iteration 1 : Mainly used for resubscribing request. All the entries
+ // corresponding to the uri which've been subscribed for before and are
+ // present in this parameter set are removed
+
+ CUPnPSubscribeRequestParamSet* paramSet = NULL;
+ TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ;
+
+ for ( paramIndex = count - 1; paramIndex >= 0; paramIndex-- )
+ {
+ paramSet = static_cast<CUPnPSubscribeRequestParamSet*> ( family.GetParameterSetAtIndex ( paramIndex, RParameterFamily::ERequested ) );
+
+ const TDesC8& uri = paramSet->Uri();
+ __ASSERT_DEBUG( paramSet->Uri() != KNullDesC8, User::Panic( KUPnPInvalidUserInput, KUPnPErrInvalidInput ) );
+ __ASSERT_DEBUG( paramSet->Duration() > 0, User::Panic( KUPnPInvalidUserInput, KUPnPErrInvalidInput ) );
+
+ for(TInt i=0;i<iTimerMappedArray.Count();i++)
+ {
+ if(iTimerMappedArray[i]->UriExists(uri))
+ {
+ CTimerMappedUri* timerUri = iTimerMappedArray[i];
+ iDeltaTimer->Remove(timerUri->GetTimerEntry());
+ iTimerMappedArray.Remove(i);
+ delete timerUri;
+ break;
+ }
+ }
+ for( TInt i=0;i<iCallbackArray.Count();i++)
+ {
+ if(uri.CompareF(iCallbackArray[i]->GetUri()) == NULL)
+ {
+ CCallbackArgument* callArgument = iCallbackArray[i];
+ iCallbackArray.Remove(i);
+ delete callArgument;
+ break;
+ }
+ }
+
+ if( iElementArray && iElementArray->MatchElement(uri))
+ iElementArray->RemoveElement(uri);
+
+ }
+ // Initialize the iterator . The uris will be checked for duplication,resolved
+ // and appended
+ TInetAddr address;
+
+ for ( paramIndex = count - 1; paramIndex >= 0; paramIndex-- )
+ {
+ paramSet = static_cast<CUPnPSubscribeRequestParamSet*> ( family.GetParameterSetAtIndex ( paramIndex, RParameterFamily::ERequested ) );
+ const TDesC8& uri = paramSet->Uri();
+
+ // Creates a new Element array if one is not already present and
+ // appends the uri to it. If the uri is duplicate then the corresponding param
+ // set is removed
+ if(!iElementArray)
+ {
+ iElementArray = new CUPnPElementArray;
+ User::LeaveIfNull(iElementArray);
+ iElementArray->InsertElementL(aServiceInfo.PnPObserver(), uri);
+ }
+ else
+ {
+ if(!iElementArray->MatchElement(uri))
+ {
+ iElementArray->InsertElementL(aServiceInfo.PnPObserver(),uri);
+ }
+ else
+ {
+ reinterpret_cast<RUPnPParameterFamily*>(&family)->DeleteParamSetL(paramIndex);
+ continue;
+ }
+ }
+
+ CUPnPUtils::ResolveHostAddressL ( iResolver, paramSet->Uri(), address );
+ paramSet->SetRemoteHost ( address );
+
+ }
+ /* Finally if all other processing is done successfully do the
+ * set params
+ */
+
+ if ( family.CountParameterSets(RParameterFamily::ERequested)>=1)
+ User::LeaveIfError(iSubConnection.SetParameters(aServiceInfo));
+
+
+ }
+
+/* On expiry of the CDeltaTimer associated with the requested uri
+ * it removes the corresponding from the element array and notifies the client
+ */
+TInt CUPnPSubscribe::OnTimerExpiry(TAny* aPtr)
+ {
+ TInt error = KErrNone;
+ CCallbackArgument* pointerData= static_cast<CCallbackArgument*> (aPtr);
+ CUPnPSubscribe* thisObject= static_cast<CUPnPSubscribe*> (pointerData->GetThisPointer());
+ CUPnPElementArray* thisElementArray=thisObject->ElementArrayHandle();
+ RPointerArray<CTimerMappedUri>& timerArray=thisObject->GetTimerArray();
+ RPointerArray<CCallbackArgument>& argArray = thisObject->GetArgumentArray();
+
+ const TDesC8& uri = pointerData->GetUri();
+
+ TInt index;
+ for( index=0; index<timerArray.Count(); index++ )
+ {
+ if(timerArray[index]->UriExists(uri))
+ {
+ CTimerMappedUri* timerUri = timerArray[index];
+ timerArray.Remove(index);
+ delete timerUri;
+ index = -1;
+ break;
+ }
+ }
+ __ASSERT_DEBUG( index == -1 ,User::Panic(KUPnPTimerUriNotFound,KUPnPErrTimerError) );
+ for( index=0; index<argArray.Count(); index++ )
+ {
+ const TDesC8& testUri = argArray[index]->GetUri();
+ if(uri.CompareF(argArray[index]->GetUri())==NULL)
+ {
+ argArray.Remove(index);
+ break;
+ }
+ }
+ MPnPObserver* observer = thisElementArray->MatchElement(uri);
+ __ASSERT_DEBUG( observer , User::Invariant());
+ // Removes the uri from the element Array
+ HBufC8* notifyUri = pointerData->GetUri().Alloc();
+ __ASSERT_DEBUG( notifyUri , User::Invariant());
+
+ // Deletes the CCallbackargument data
+ delete pointerData;
+
+ // Notifies the client that timer has expired
+ TRAP(error,thisObject->MakeBundleAndNotifyL(observer, notifyUri));
+ return KErrNone;
+ }
+
+/* Passes back the response bundle to the client. A response bundle
+ will contain only one parameter set consequently with a single observer
+ */
+void CUPnPSubscribe::NotifyResultsL(TUint32 aFamilyId, RPnPParameterBundleBase& aBundle)
+ {
+ MPnPObserver* observer = NULL;
+ User::LeaveIfNull(iElementArray);
+
+ CUPnPSubscribeResponseParamSet* subscribeParamSet = NULL;
+ CUPnPNotifyEventParamSet* notifyParamSet = NULL;
+ RParameterFamily family ;
+ switch(aFamilyId)
+ {
+ case EUPnPSubscribeResponseParamSet:
+ {
+ // Response to subscription request
+ family = aBundle.FindFamily(EUPnPSubscribeResponseParamSet);
+ __ASSERT_DEBUG(!family.IsNull (), User::Panic(KUPnPInvalidFamily,KUPnPErrInvalidFamily));
+ __ASSERT_DEBUG(family.CountParameterSets(RParameterFamily::ERequested) > 0, User::Panic(KUPnPNoParamSet,KUPnPErrNoParamSet));
+ TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ;
+ for ( TInt paramIndex = count - 1; paramIndex >= 0; paramIndex-- )
+ {
+ subscribeParamSet = static_cast<CUPnPSubscribeResponseParamSet*> (family.GetParameterSetAtIndex(paramIndex,RParameterFamily::ERequested));
+ switch(( subscribeParamSet->UPnPEvent() ).iStatus)
+ {
+ case TUPnPEvent::ESuccess:
+ {
+ /* Extract the uri and the expiry time which has been supplied by
+ * the server and create a deltatimer entry using them
+ */
+ TInt subscribeExpiryTime = subscribeParamSet->GetTimerExpiry();
+ const TDesC8& uri = subscribeParamSet->Uri();
+ observer = iElementArray->MatchElement(uri);
+ __ASSERT_DEBUG( observer != NULL, User::Panic(KUPnPResponseUriNotFound,KUPnPErrResponseUriNotFound));
+
+ CreateTimerEntryL(uri,subscribeExpiryTime);
+ }
+ break;
+
+ case TUPnPEvent::EFail:
+ {
+ const TDesC8& uri = subscribeParamSet->Uri();
+ observer=iElementArray->MatchElement(uri);
+ __ASSERT_DEBUG( observer != NULL, User::Panic(KUPnPResponseUriNotFound,KUPnPErrResponseUriNotFound));
+ iElementArray->RemoveElement(uri);
+ }
+ break;
+
+ default:
+ __ASSERT_DEBUG(0, User::Panic(KUPnPInvalidFamily,KUPnPErrInvalidFamily));
+ }
+ }
+ }
+ break;
+
+ case EUPnPNotifyEventParamSet:
+ {
+
+ // Eventing parameter set
+ family = aBundle.FindFamily( EUPnPNotifyEventParamSet );
+ TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ;
+ notifyParamSet = static_cast<CUPnPNotifyEventParamSet*> ( family.GetParameterSetAtIndex ( count - 1, RParameterFamily::ERequested ) );
+ observer = iElementArray->MatchElement(notifyParamSet->Uri());
+ __ASSERT_DEBUG( observer != NULL, User::Panic(KUPnPResponseUriNotFound,KUPnPErrResponseUriNotFound));
+ }
+ break;
+ default:
+ __ASSERT_DEBUG(0, User::Panic(KUPnPInvalidFamily,KUPnPErrInvalidFamily));
+ }
+
+ observer->OnPnPEventL(aBundle) ;
+ }
+
+/* Makes a bundle on expiry of the timer and sends it the client application
+ * saying "Subscription has timed out"
+ */
+void CUPnPSubscribe::MakeBundleAndNotifyL(MPnPObserver* aObserver, HBufC8* aUri)
+ {
+ RPnPParameterBundleBase pnpBundle ;
+ pnpBundle.Open();
+ CleanupClosePushL( pnpBundle );
+
+ RParameterFamily family = pnpBundle.CreateFamilyL(EUPnPSubscribeResponseParamSet);
+ // Create a new Param set
+ CUPnPSubscribeResponseParamSet* subscribeParamSet = CUPnPSubscribeResponseParamSet::NewL(family );
+
+ // Set the values for the event
+ TUPnPEvent event;
+ event.iStatus=TUPnPEvent::ESubscriptionTimeout;
+ event.iErrorCode = KErrTimedOut;
+
+ // Set the values in the parameter set
+ subscribeParamSet->SetUPnPEvent(event);
+ subscribeParamSet->SetUriL ( *aUri );
+ subscribeParamSet->SetTimerExpiry(NULL);
+
+ CleanupStack::Pop( &pnpBundle);
+ delete aUri;
+ aObserver->OnPnPEventL( pnpBundle ) ;
+ }
+
+/* CancelDescribe is used to send cancel subscribe requests to the network
+ @param aServiceInfo The bundle which contains the list of uris whose describe
+ request should be cancelled
+ */
+void CUPnPSubscribe::CancelSubscribeL( const RPnPParameterBundle& aServiceInfo )
+ {
+ User::LeaveIfNull(iElementArray);
+ RParameterFamily family = const_cast<RPnPParameterBundle&>(aServiceInfo).FindFamily( EUPnPCancelSubscribeParamSet );
+
+ CUPnPCancelSubscribeParamSet* paramSet = NULL;
+ TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ;
+
+ for ( TInt paramIndex = count - 1; paramIndex >= 0; paramIndex-- )
+ {
+ paramSet = static_cast<CUPnPCancelSubscribeParamSet*> ( family.GetParameterSetAtIndex ( paramIndex, RParameterFamily::ERequested) );
+ //Extract the uri
+ const TDesC8& uri = paramSet->Uri();
+ __ASSERT_DEBUG( paramSet->Uri() != KNullDesC8, User::Panic( KUPnPInvalidUserInput, KUPnPErrInvalidInput ) );
+
+ // Removes the uri entry from the array if exists
+ for(TInt i=0;i<iTimerMappedArray.Count();i++)
+ {
+ if(iTimerMappedArray[i]->UriExists(uri) )
+ {
+ CTimerMappedUri* timerUri = iTimerMappedArray[i];
+ iDeltaTimer->Remove(timerUri->GetTimerEntry());
+ iTimerMappedArray.Remove(i);
+ delete timerUri;
+ break;
+ }
+ }
+ for( TInt i=0;i<iCallbackArray.Count();i++)
+ {
+ if(uri.CompareF(iCallbackArray[i]->GetUri()) == NULL)
+ {
+ CCallbackArgument* callArgument = iCallbackArray[i];
+ iCallbackArray.Remove(i);
+ delete callArgument;
+ break;
+ }
+ }
+
+ // Remove the entry from element array
+ MPnPObserver* observer = iElementArray->MatchElement( uri );
+ if ( !observer )
+ {
+ reinterpret_cast<RUPnPParameterFamily*>(&family)->DeleteParamSetL ( paramIndex );
+ continue;
+ }
+ iElementArray->RemoveElement( uri );
+ }
+ if ( family.CountParameterSets(RParameterFamily::ERequested) >= 1)
+ User::LeaveIfError(iSubConnection.SetParameters( aServiceInfo ));
+
+ }
+
+/* The timer delay is adjusted to 90% of the subscription time.Also it is adjusted
+ for microseconds and IPC lag
+ */
+TInt CUPnPSubscribe::AdjustedDelay( TInt aTime )
+ {
+ TUint64 divisor = 10;
+ TUint64 temp; // just a placeholder
+ TUint64 q = Math::UDivMod64(aTime,divisor,temp);
+ temp = q*(divisor-1);
+ aTime = static_cast<TInt>(temp);
+
+ const TInt KIntTime = 1000000 ;
+ const TInt KInternalIPCLag = 1;
+ aTime = ( aTime + KInternalIPCLag ) * KIntTime ;
+ return aTime;
+ }
+
+/* CreateTimerEntry : creates the deltatimer entry and queues it up
+ */
+void CUPnPSubscribe::CreateTimerEntryL(const TDesC8& aUri ,TInt aExpiryTime)
+
+ {
+ CCallbackArgument* callArgument = CCallbackArgument::NewL(this,aUri);
+ CleanupStack::PushL(callArgument);
+ iCallbackArray.AppendL(callArgument);
+ CleanupStack::Pop();
+
+ TCallBack callBack(OnTimerExpiry,callArgument);
+ iTimerEntry = new(ELeave) TDeltaTimerEntry( callBack );
+ iMappedUri = CTimerMappedUri::NewL(aUri, iTimerEntry,aExpiryTime);
+ iTimerMappedArray.AppendL(iMappedUri);
+
+ // The time is set to 90% of the given time to allow the user
+ // to resubscribe before the expiry time
+ TInt time = AdjustedDelay(aExpiryTime);
+ TTimeIntervalMicroSeconds32 delay(time);
+ iDeltaTimer->Queue(delay,*iTimerEntry);
+ }
+
+