servicediscoveryandcontrol/pnp/test/upnp/Client/upnpplugin/src/cupnpsubscribe.cpp
changeset 0 f5a58ecadc66
--- /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);
+	}
+
+