diff -r 000000000000 -r f5a58ecadc66 servicediscoveryandcontrol/pnp/test/upnp/Client/upnpplugin/src/cupnpsubscribe.cpp --- /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 + +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(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 ( 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;iUriExists(uri)) + { + CTimerMappedUri* timerUri = iTimerMappedArray[i]; + iDeltaTimer->Remove(timerUri->GetTimerEntry()); + iTimerMappedArray.Remove(i); + delete timerUri; + break; + } + } + for( TInt i=0;iGetUri()) == 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 ( 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(&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 (aPtr); + CUPnPSubscribe* thisObject= static_cast (pointerData->GetThisPointer()); + CUPnPElementArray* thisElementArray=thisObject->ElementArrayHandle(); + RPointerArray& timerArray=thisObject->GetTimerArray(); + RPointerArray& argArray = thisObject->GetArgumentArray(); + + const TDesC8& uri = pointerData->GetUri(); + + TInt index; + for( index=0; indexUriExists(uri)) + { + CTimerMappedUri* timerUri = timerArray[index]; + timerArray.Remove(index); + delete timerUri; + index = -1; + break; + } + } + __ASSERT_DEBUG( index == -1 ,User::Panic(KUPnPTimerUriNotFound,KUPnPErrTimerError) ); + for( index=0; indexGetUri(); + 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 (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 ( 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(aServiceInfo).FindFamily( EUPnPCancelSubscribeParamSet ); + + CUPnPCancelSubscribeParamSet* paramSet = NULL; + TUint count = family.CountParameterSets ( RParameterFamily::ERequested ) ; + + for ( TInt paramIndex = count - 1; paramIndex >= 0; paramIndex-- ) + { + paramSet = static_cast ( 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;iUriExists(uri) ) + { + CTimerMappedUri* timerUri = iTimerMappedArray[i]; + iDeltaTimer->Remove(timerUri->GetTimerEntry()); + iTimerMappedArray.Remove(i); + delete timerUri; + break; + } + } + for( TInt i=0;iGetUri()) == 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(&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(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); + } + +