diff -r 000000000000 -r f5a58ecadc66 upnp/upnpstack/upnputils/src/upnpdevicelibrary.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnp/upnpstack/upnputils/src/upnpdevicelibrary.cpp Tue Feb 02 01:12:20 2010 +0200 @@ -0,0 +1,763 @@ +/** @file +* Copyright (c) 2005-2008 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: CUpnpDeviceLibrary +* +*/ + + +// INCLUDE FILES +#include "upnpdevicelibrary.h" +#include "upnpssdpmessage.h" +#define KLogFile _L("DLNAWebServer.txt") +#include "upnpcustomlog.h" + +static const TInt KIntervalBetweenByeAndAlive = 1; +static const TInt KIntervalBeforeFirstAlive = 1; +// prevents treating SSDP alive messages sent by local device +// as an external device messages in case of quick local device restarting +// heuristic value +static const TInt KLocalDeviceHysteresisWindow = 20; +// used for IPC communication 2 phase request +// heuristic value +static const TInt KIpcCommunicationTimeout = 2; + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::CUpnpDeviceLibrary +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CUpnpDeviceLibrary::CUpnpDeviceLibrary( MUpnpDeviceLibraryObserver& aObserver, + TInt aHandle ) + : iObserver(aObserver), + iHandle( aHandle ) + { + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CUpnpDeviceLibrary::ConstructL() + { + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C CUpnpDeviceLibrary* CUpnpDeviceLibrary::NewL( + MUpnpDeviceLibraryObserver& aObserver, + TInt aHandle ) + { + CUpnpDeviceLibrary* self = new (ELeave) CUpnpDeviceLibrary( aObserver, aHandle ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::~CUpnpDeviceLibrary +// Destructor +// ----------------------------------------------------------------------------- +// +EXPORT_C CUpnpDeviceLibrary::~CUpnpDeviceLibrary() + { + LOGSH( iHandle, "Devicelibrary ~CUpnpDeviceLibrary"); + + iElementArray.ResetAndDestroy(); + iElementArray.Close(); + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::PrepareShutdown +// Prepare devices for shutdown. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::PrepareShutdown() + { + LOGSH( iHandle, "Devicelibrary PrepareShutdown" ); + + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::AddInfoL +// Add device info. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::AddInfoL( const TUpnpAddLocalDevice* aIndex, + const TDesC8& aBuffer, + const TInetAddr& aLocalAddr ) + { + LOGSH( iHandle, "Devicelibrary AddInfoL" ); + if ( !aIndex ) + { + return; + } + + TPtrC8 uuid = aBuffer.Left(aIndex->iUuidLength); + TInt index = Find( uuid ); + + if ( index != KErrNotFound ) + { + CUpnpDeviceLibraryElement* elem = iElementArray[index]; + + if ( elem->Local() ) + { + CUpnpTimeoutElement::TRenew state = elem->Renew(); + elem->AddInfoL( aIndex, aBuffer, aLocalAddr ); + elem->SetRenew( CUpnpTimeoutElement::ERenew ); + elem->SetTimeout( KIntervalBeforeFirstAlive ); + elem->SetUpdateId( iUpdateId ); + + if ( state == CUpnpTimeoutElement::ERemove ) + { + elem->SetAlive( ETrue ); + elem->SetUpdateId( ++iUpdateId ); + iObserver.DeviceListChangedL(); + } + } + else + { + InvalidateNonLocalDevice( *elem ); + AppendLocalDeviceL( aIndex, aBuffer, aLocalAddr ); + iObserver.DeviceListChangedL(); + } + } + else + { + AppendLocalDeviceL( aIndex, aBuffer, aLocalAddr ); + iObserver.DeviceListChangedL(); + } + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::InvalidateNonLocalDevice +// ----------------------------------------------------------------------------- +// +void CUpnpDeviceLibrary::InvalidateNonLocalDevice( CUpnpDeviceLibraryElement& aElem ) + { + aElem.SetAlive( EFalse ); + aElem.SetUpdateId( ++iUpdateId ); + aElem.SetTimeout( KIpcCommunicationTimeout ); + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::AppendLocalDeviceL +// ----------------------------------------------------------------------------- +// +void CUpnpDeviceLibrary::AppendLocalDeviceL( const TUpnpAddLocalDevice* aIndex, + const TDesC8& aBuffer, + const TInetAddr& aLocalAddr ) + { + CUpnpDeviceLibraryElement* element = CUpnpDeviceLibraryElement::NewL(*this); + CleanupStack::PushL( element ); + element->AddInfoL( aIndex, aBuffer, aLocalAddr ); + element->SetRenew( CUpnpTimeoutElement::ERenew ); + element->SetTimeout( KIntervalBeforeFirstAlive ); + element->SetLocal( ETrue ); + element->SetUpdateId( ++iUpdateId ); + iElementArray.AppendL( element ); + CleanupStack::Pop( element ); + } +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::AddInfoL +// Add device info. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::AddInfoL( const TUpnpAddLocalDevice* aIndex, + const TDesC8& aBuffer ) + { + LOGSH( iHandle, "Devicelibrary AddInfoL"); + + if ( !aIndex ) + { + return; + } + + TPtrC8 uuid = aBuffer.Left(aIndex->iUuidLength); + + TInt index = Find( uuid ); + + if ( index != KErrNotFound ) + { + CUpnpDeviceLibraryElement* elem = iElementArray[index]; + + CUpnpTimeoutElement::TRenew state = elem->Renew(); + + elem->AddInfoL( aIndex, aBuffer ); + elem->SetRenew( CUpnpTimeoutElement::ERenew ); + elem->SetTimeout( 1 ); + elem->SetUpdateId( iUpdateId ); + + if (state == CUpnpTimeoutElement::ERemove) + { + iUpdateId++; + elem->SetAlive( ETrue ); + elem->SetUpdateId( iUpdateId ); + iObserver.DeviceListChangedL(); + } + } + else + { + iUpdateId++; + + CUpnpDeviceLibraryElement* element = CUpnpDeviceLibraryElement::NewL(*this); + CleanupStack::PushL( element ); + element->AddInfoL( aIndex, aBuffer ); + element->SetRenew( CUpnpTimeoutElement::ERenew ); + element->SetTimeout( 1 ); + element->SetLocal( EFalse ); + element->SetUpdateId( iUpdateId ); + iElementArray.AppendL( element ); + CleanupStack::Pop( element ); + + iObserver.DeviceListChangedL(); + } + } +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::AddInfoL +// Add device info. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::AddInfoL( CUpnpSsdpMessage* aMessage ) + { + LOGSH( iHandle, "Devicelibrary AddInfoL"); + if ( aMessage ) + { + if ( aMessage->IsSsdpAlive() ) + { + if( AddDeviceL(aMessage) ) + { + iObserver.DeviceListChangedL(); + } + } + else + { + RemoveDeviceL( aMessage ); + iObserver.DeviceListChangedL(); + } + } + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::Find +// Find device given by UUID. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CUpnpDeviceLibrary::Find( const TDesC8& aUuid ) + { + LOGSH( iHandle, "Devicelibrary Find"); + + for ( TInt i=0; iUUID() ) == 0 + && aUuid.Length() == iElementArray[i]->UUID().Length() ) + { + return i; + } + } + return KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::RemoveL +// Remove device by given UID. Used for local devices only. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::RemoveL( const TDesC8& aUuid ) + { + LOGSH( iHandle, "Devicelibrary RemoveL"); + + TInt result = Find( aUuid ); + + if ( result != KErrNotFound ) + { + CUpnpDeviceLibraryElement* elem = iElementArray[result]; + + iObserver.AdvertiseDeviceL( EFalse, *elem ); + iObserver.AdvertiseDeviceL( EFalse, *elem ); + + elem->AdvertisingFinished(); + + elem->SetRenew( CUpnpTimeoutElement::ERemove ); + elem->SetTimeout( KLocalDeviceHysteresisWindow ); + elem->SetUpdateId( ++iUpdateId ); + elem->SetAlive( EFalse ); + + iObserver.DeviceListChangedL(); + } + } +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::RemoveSilentL +// Remove device by given UID. Used for local devices only. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::RemoveSilentL( const TDesC8& aUuid ) + { + //LOGS( iHandle, "Devicelibrary RemoveSilentL"); + + LOGS("CUpnpDeviceLibrary::RemoveSilentL( const TDesC8& aUuid )"); + TInt result = Find( aUuid ); + + if ( result != KErrNotFound ) + { + CUpnpDeviceLibraryElement* elem = iElementArray[result]; + + + elem->SetRenew( CUpnpTimeoutElement::ERemove ); + elem->SetTimeout( KLocalDeviceHysteresisWindow ); + elem->SetUpdateId( ++iUpdateId ); + elem->SetAlive( EFalse ); + + iObserver.DeviceListChangedL(); + } + LOGS("CUpnpDeviceLibrary::RemoveSilentL( const TDesC8& aUuid ) passed"); + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::TimeoutExpiredL +// Timeout expired for advertisement. +// ----------------------------------------------------------------------------- +// +void CUpnpDeviceLibrary::TimeoutExpiredL( CUpnpTimeoutElement* anElement ) + { + LOGSH( iHandle, "Devicelibrary TimeoutExpiredL"); + + if ( !anElement ) + { + return; + } + + CUpnpDeviceLibraryElement* elem = + static_cast(anElement); + + switch ( elem->Renew() ) + { + case CUpnpTimeoutElement::ERenew: + { + if ( !elem->Advertised() ) + { + elem->Advertising(); + // whatever happends we don't want to have leave here + TRAP_IGNORE( iObserver.AdvertiseDeviceL( EFalse, *elem )); + TRAP_IGNORE( iObserver.AdvertiseDeviceL( EFalse, *elem )); + elem->SetTimeout( KIntervalBetweenByeAndAlive ); + } + else + { + // whatever happends we don't want to have leave here + TRAP_IGNORE( iObserver.AdvertiseDeviceL( ETrue, *elem )); + elem->SetTimeout( KDeviceTimeout ); + } + } + break; + + case CUpnpTimeoutElement::EOnce: // after cache control expires + { + // Set the timeout for the device to be removed + iUpdateId++; + elem->SetRenew( CUpnpTimeoutElement::ERemove ); + if( elem->Local() ) + { + elem->SetTimeout( KLocalDeviceHysteresisWindow ); + } + else + { + elem->SetTimeout( KIpcCommunicationTimeout ); + } + elem->SetUpdateId( iUpdateId ); + elem->SetAlive( EFalse ); + elem->SetExpired( ETrue ); + + iObserver.DeviceListChangedL(); + } + break; + + case CUpnpTimeoutElement::ERemove: + { + // Remove device from the element array + for ( TInt i=0; i& CUpnpDeviceLibrary::DeviceList() + { + LOGSH( iHandle, "Devicelibrary DeviceList"); + + return iElementArray; + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::GetUpdate +// Get update. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::GetUpdate( TInt& aUpdateId, + TUpnpDevice *&aDevices, + TUpnpService *&aServices, + TInt& aDeviceCount, + TInt& aServiceCount ) + { + aDevices = NULL; + aServices = NULL; + + TUpnpDevice* devices = NULL; + TUpnpService* services = NULL; + + aDeviceCount = 0; + aServiceCount = 0; + + for ( TInt i = 0; i < iElementArray.Count(); i++ ) + { + CUpnpDeviceLibraryElement* elem = iElementArray[i]; + + if (elem->UpdateId() > aUpdateId) + { + TUpnpDevice* temp = new TUpnpDevice[aDeviceCount+1]; + if ( !temp ) + { + continue; + } + + TPtr8 destPtr(reinterpret_cast(temp), + 0, + sizeof(TUpnpDevice)*(aDeviceCount+1)); + TPtr8 srcPtr(reinterpret_cast(devices), + sizeof(TUpnpDevice)*aDeviceCount, + sizeof(TUpnpDevice)*aDeviceCount); + + destPtr.Copy(srcPtr); + + if (devices) + { + delete[] devices; + devices = NULL; + } + + devices = temp; + + TUpnpDevice devtemp; + destPtr.Set(reinterpret_cast(&devices[aDeviceCount]), + 0, + sizeof(TUpnpDevice)); + srcPtr.Set(reinterpret_cast(&devtemp), + sizeof(TUpnpDevice), + sizeof(TUpnpDevice)); + destPtr.Copy(srcPtr); + + devices[aDeviceCount].Set(elem); + + TInt servs = elem->ServiceList().Count(); + + TUpnpService* tempServ = new TUpnpService[aServiceCount+servs]; + if ( !tempServ ) + { + delete [] temp; + temp = NULL; + devices = NULL; + continue; + } + + destPtr.Set(reinterpret_cast(tempServ), + 0, + sizeof(TUpnpService)*(aServiceCount+servs)); + srcPtr.Set(reinterpret_cast(services), + sizeof(TUpnpService)*aServiceCount, + sizeof(TUpnpService)*aServiceCount); + + destPtr.Copy(srcPtr); + + if (services) + { + delete[] services; + services = NULL; + } + + services = tempServ; + + for (TInt j=0; j(&services[aServiceCount]), + 0, + sizeof(TUpnpService)); + srcPtr.Set(reinterpret_cast(&service), + sizeof(TUpnpService), + sizeof(TUpnpService)); + destPtr.Copy(srcPtr); + + services[aServiceCount].iServiceType.Zero(); + services[aServiceCount].iServiceType.Append( + elem->ServiceList()[j] ); + + aServiceCount++; + } + + aDeviceCount++; + } + } + + aUpdateId = iUpdateId; + + aDevices = devices; + aServices = services; + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::RemoveAllDevicesL +// Removes all remote devices from device library. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::RemoveAllDevicesL() + { + for (TInt i = 0; i < iElementArray.Count(); i++) + { + CUpnpDeviceLibraryElement* elem = iElementArray[i]; + if ( elem->Alive() ) + { + iUpdateId++; + elem->SetAlive(EFalse); + elem->SetUpdateId( iUpdateId ); + if( elem->Renew() == CUpnpTimeoutElement::EOnce ) + { + elem->SetRenew( CUpnpTimeoutElement::ERemove ); + elem->SetTimeout( KIpcCommunicationTimeout ); + } + } + } + iObserver.DeviceListChangedL(); + } + +// ----------------------------------------------------------------------------- +// TUpnpDevice::Set +// Set device. +// ----------------------------------------------------------------------------- +// +EXPORT_C void TUpnpDevice::Set(CUpnpDeviceLibraryElement* aElem) + { + LOGS("Devicelibrary Set"); + + if ( !aElem ) + { + return; + } + + iDescriptionURL = aElem->DescriptionUrl().Left( iDescriptionURL.MaxLength() ); + iUUID = aElem->UUID().Left( iUUID.MaxLength() ); + iDeviceType = aElem->DeviceType().Left( iDeviceType.MaxLength() ); + iDomain = aElem->Domain().Left( iDomain.MaxLength() ); + + iServiceCount = aElem->ServiceList().Count(); + iLocal = aElem->Local(); + iRemote = EFalse; + iAlive = aElem->Alive(); + iExpired = aElem->Expired(); + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::AddDeviceL +// Add a device. +// ----------------------------------------------------------------------------- +// +TBool CUpnpDeviceLibrary::AddDeviceL(CUpnpSsdpMessage *aMessage) + { + TBool update = EFalse; + + LOGSH( iHandle, "Devicelibrary AddDeviceL"); + + if ( !aMessage ) + { + return update; + } + + TPtr8 uuidPtr = aMessage->Uuid(); + TInt index = Find( uuidPtr ); + + if (index != KErrNotFound) + { + CUpnpDeviceLibraryElement* elem = iElementArray[index]; + if ( !elem->Local() ) + { + if( elem->Renew() == CUpnpTimeoutElement::ERemove ) + { + iElementArray.Remove( index ); + iElementArray.Compress(); + + delete elem; + + CUpnpDeviceLibraryElement* element = CUpnpDeviceLibraryElement::NewL(*this); + CleanupStack::PushL(element); + + update = element->AddInfoL(aMessage, iUpdateId); + + element->SetRenew(CUpnpTimeoutElement::EOnce); + element->SetTimeout(aMessage->CacheControl()); + element->SetLocal(EFalse); + iElementArray.Append(element); + + CleanupStack::Pop(); // element + } + + else + { + if(elem->Filter()) + { + //Alive message from + if(elem->AddInfoL(aMessage, iUpdateId)) + { + update=ETrue; + } + elem->SetTimeout(aMessage->CacheControl()); + } + else + { + iElementArray.Remove( index ); + iElementArray.Compress(); + + delete elem; + + CUpnpDeviceLibraryElement* element = CUpnpDeviceLibraryElement::NewL(*this); + CleanupStack::PushL(element); + + update = element->AddInfoL(aMessage, iUpdateId); + + element->SetRenew(CUpnpTimeoutElement::EOnce); + element->SetTimeout(aMessage->CacheControl()); + element->SetLocal(EFalse); + iElementArray.Append(element); + + CleanupStack::Pop(); // element + } + } + } + } + else + { + CUpnpDeviceLibraryElement* element = CUpnpDeviceLibraryElement::NewL(*this); + CleanupStack::PushL(element); + + update = element->AddInfoL(aMessage, iUpdateId); + + element->SetRenew(CUpnpTimeoutElement::EOnce); + element->SetTimeout(aMessage->CacheControl()); + element->SetLocal(EFalse); + iElementArray.Append(element); + + CleanupStack::Pop(); // element + } + return update; + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::RemoveDevice +// Remove a device. +// ----------------------------------------------------------------------------- +// +void CUpnpDeviceLibrary::RemoveDeviceL( CUpnpSsdpMessage *aMessage ) + { + LOGSH( iHandle, "Devicelibrary RemoveDevice" ); + + if ( !aMessage ) + { + return; + } + + TPtr8 uuidPtr = aMessage->Uuid(); + TInt index = Find( uuidPtr ); + + if ( index != KErrNotFound ) + { + CUpnpDeviceLibraryElement* elem = iElementArray[index]; + if ( !elem->Local() ) + { + if ( elem->Alive() ) + { + iUpdateId++; + elem->SetAlive(EFalse); + elem->SetUpdateId( iUpdateId ); + if( elem->Renew() == CUpnpTimeoutElement::EOnce ) + { + elem->SetRenew( CUpnpTimeoutElement::ERemove ); + elem->SetTimeout( KIpcCommunicationTimeout ); + } + } + iObserver.DeviceListChangedL(); + } + } + else + { + CUpnpDeviceLibraryElement* element = CUpnpDeviceLibraryElement::NewL( *this ); + CleanupStack::PushL( element ); + + element->AddInfoL( aMessage, iUpdateId ); + + iUpdateId++; + element->SetAlive( EFalse ); + element->SetUpdateId( iUpdateId ); + element->SetRenew( CUpnpTimeoutElement::ERemove ); + element->SetTimeout( KIpcCommunicationTimeout ); + element->SetLocal( EFalse ); + iElementArray.AppendL( element ); + + CleanupStack::Pop( element ); + + iObserver.DeviceListChangedL(); + } + } + +// ----------------------------------------------------------------------------- +// CUpnpDeviceLibrary::StopFilteringDeviceL +// ----------------------------------------------------------------------------- +// +EXPORT_C void CUpnpDeviceLibrary::StopFilteringDeviceL( const TDesC8& aUuid ) + { + LOGSH( iHandle, "Devicelibrary RemoveDevice" ); + + TInt index = Find( aUuid ); + + if ( index != KErrNotFound ) + { + CUpnpDeviceLibraryElement* elem = iElementArray[index]; + elem->SetFilter(EFalse); + } + } + +// End of File