upnpavcontroller/upnpavcontrollerserver/src/upnpavcontrollerserver.cpp
author Sampo Huttunen <sampo.huttunen@nokia.com>
Thu, 18 Nov 2010 15:46:57 +0200
branchIOP_Improvements
changeset 44 97caed2372ca
parent 38 5360b7ddc251
permissions -rw-r--r--
Fixed AVController, it was accidentally set to search only for renderers. Now also servers are added to device list. Also some minor changes in package definition xml and platform API xml definition files.

/*
* Copyright (c) 2006-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:      AVController server
*
*/







// INCLUDE FILES
// System
#include <e32svr.h>
#include <f32file.h> 

// upnp stack
#include <upnpdevice.h>
#include <upnpsettings.h>

// dlnasrv / avcontroller api
#include "upnpavcontrollerglobals.h"

// dlnasrv / internal api's
#include "upnpconnectionmonitor.h"

// dlnasrv / avcontroller server internal
#include "upnpavcontrollerserver.h"
#include "upnpavcontrollersession.h"
#include "upnpavcontrolpoint.h"
#include "upnpavdispatcher.h"
#include "upnpdevicerepository.h"
#include "upnpavdeviceextended.h"
#include "upnpaverrorhandler.h"
#include "upnpavcpstrings.h"

_LIT( KComponentLogfile, "upnpavcontrollerserver.txt" );
#include "upnplog.h"

using namespace UpnpAVCPStrings;

// CONSTANTS
_LIT8( KUPnPRootDevice,                 "upnp:rootdevice" );

const TUint KMyRangeCount = 3;

const TInt KMyRanges[ KMyRangeCount ] = 
    {
    0, // numbers 0-18
    18, // numbers 18-EAVControllerRqstLast
    EAVControllerRqstLast // numbers EAVControllerRqstLast-KMaxInt
    };

const TUint8 KMyElementsIndex[ KMyRangeCount ] = 
    {
    0, 
    1, 
    CPolicyServer::ENotSupported
    };
    
const CPolicyServer::TPolicyElement KMyElements[] = 
    {
    {_INIT_SECURITY_POLICY_C3(ECapabilityNetworkServices,
        ECapabilityReadUserData, ECapabilityWriteUserData ),
        CPolicyServer::EFailClient },
    {_INIT_SECURITY_POLICY_C1(ECapabilityNetworkServices),
        CPolicyServer::EFailClient}
    };
    
const CPolicyServer::TPolicy KMyPolicy =
    {
    CPolicyServer::EAlwaysPass, //specifies all connect attempts should pass
    KMyRangeCount,                   
    KMyRanges,
    KMyElementsIndex,
    KMyElements,
    };

// ============================ MEMBER FUNCTIONS ============================

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::CUpnpAVControllerServer
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
CUpnpAVControllerServer::CUpnpAVControllerServer( TInt aPriority ):
    CPolicyServer( aPriority, KMyPolicy ),
    iShutdownTimeoutValue( KTimerCycle10 ),
    iState( EStateUndefined )
    {    
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::ConstructL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::ConstructL()
    {
    __LOG( "CUpnpAVControllerServer::ConstructL" );

    ChangeState( EStateStartingServer );

    __LOG( "ConstructL - Starting server" );

    // create av dispatcher
    iDispatcher = CUPnPAVDispatcher::NewL( *this );

    // create av control point
    iAVControlPoint = CUpnpAVControlPoint::NewL( *iDispatcher );    
    
    // create device repository
    iDeviceRepository = CUPnPDeviceRepository::NewL( *iAVControlPoint );
    
    iUpnpSettings = CUpnpSettings::NewL( KCRUidUPnPStack );
    iUpnpSettings->Get( CUpnpSettings::KUPnPStackIapId, iIAP );
    
    iMonitor = CUPnPConnectionMonitor::NewL( iIAP );
    iMonitor->SetObserver( *this );
    
    StartL( KAVControllerName );   
    
    iServerTimer = CUPnPAVTimer::NewL( *this,
        CUPnPAVTimer::ETimerServerShutdown );
    
    iServerTimer->Start( iShutdownTimeoutValue );

    iIconDownloader = CUpnpDeviceIconDownloader::NewL( *this, iIAP );

    __LOG( "CUpnpAVControllerServer::ConstructL - Finished" );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::StartUpL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::StartUpL()
    {
    __LOG( "CUpnpAVControllerServer::StartUpL" );

    if( iState == EStateStartingServer )
        {
        ChangeState( EStateStartingControlPoint );

        __LOG( "StartUpL - Starting control point" );
        
        // start SSPD search
        TInt err = KErrNone;
        TRAP( err, iAVControlPoint->StartUpL() );
        if( err == KErrNone )
            {
            __LOG( "StartUpL - Searching root device" );
            
            iAVControlPoint->SearchL( KUPnPRootDevice );
            ChangeState( EStateRunning );
            }
        else
            {
            iShutdownTimeoutValue = 0;
            User::Leave( err );
            }
        }        
    else if( iState == EStateShuttingDown )
        {
        __LOG( "StartUpL - Wlan disconnected or shutting down, leave" );
        User::Leave( KErrDisconnected );
        }
    else if( iState == EStateStartingControlPoint )
        {
        __LOG( "StartUpL - Already starting control point" );
        }
    else
        {
        __LOG( "StartUpL - Server already running" );
        }

    __LOG( "StartUpL - Completed" );    
    }

void CUpnpAVControllerServer::CancelStartUp()
    {
    __LOG( "CUpnpAVControllerServer::CancelStartUp" );
    
    // Cancel can occur only when the av controller instance is deleted
    // right after the asyncronous part of the construction has been
    // started. There is no proper way to cancel, but we can set the
    // shutdown timer to 0, so the server will shutdown immidiately.
    
    if( iSessionCount <= 1 )
        {
        iShutdownTimeoutValue = 0;    
        }  
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::NewLC
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
CUpnpAVControllerServer* CUpnpAVControllerServer::NewLC()
    {
    CUpnpAVControllerServer* self = new( ELeave )
        CUpnpAVControllerServer( EPriorityNormal );   
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }
    
// --------------------------------------------------------------------------
// CUpnpAVControllerServer::~CUpnpAVControllerServer
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
CUpnpAVControllerServer::~CUpnpAVControllerServer()
    {
    __LOG( "CUpnpAVControllerServer::~CUpnpAVControllerServer" );
    
    delete iAVControlPoint;
    delete iDispatcher;
    delete iDeviceRepository;
   
    delete iMonitor;
    delete iServerTimer;
    
    delete iUpnpSettings;
    delete iIconDownloader;
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::NewSessionL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
CSession2* CUpnpAVControllerServer::NewSessionL( const TVersion& aVersion,
    const RMessage2& /*aMessage*/ ) const
    {
    __LOG( "CUpnpAVControllerServer::NewSessionL" );
    
    TInt err = KErrNone;
    
    // check if the server is shutting down
    if( iState == EStateShuttingDown )
        {
        __LOG( "NewSessionL - server shutting down, no new sessions are allowed at this point" );
        err = KErrDisconnected;
        }
        
    // Check we're the right version
    else if ( !User::QueryVersionSupported( TVersion( 
            KAVControllerMajorVersionNumber,
            KAVControllerMinorVersionNumber,
            KAVControllerBuildVersionNumber ),
            aVersion ) )
        {
        __LOG( "NewSessionL - incorrect client version" );
        err = KErrNotSupported;
        }
    
    // leave if error
    User::LeaveIfError( err );

    // Make new session
    return CUpnpAVControllerSession::NewL(
        const_cast<CUpnpAVControllerServer&>( *this ) );
    }
    
// --------------------------------------------------------------------------
// CUpnpAVControllerServer::ActionResponseL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::ActionResponseL( CUpnpAction* aAction )
    {
    if (aAction->Name().Compare( KGetProtocolInfo ) == 0)
        {
        const TDesC8& uuid = aAction->Service().Device().Uuid();
        CmProtocolInfoResponse(
            uuid,
            aAction->Error(),
            aAction->ArgumentValue( KSource ), 
            aAction->ArgumentValue( KSink )
            );
        iDispatcher->UnRegister(aAction->SessionId());
        }
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::StateUpdatedL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::StateUpdatedL( CUpnpService* /*aService*/ )
    {
    // No implementation required        
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::HttpResponseL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::HttpResponseL( CUpnpHttpMessage* /*aMessage*/ )
    {
    // No implementation required        
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DeviceDiscoveredL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::DeviceDiscoveredL( CUpnpDevice* /*aDevice*/ )
    {
    // No implementation required        
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DeviceDisappearedL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::DeviceDisappearedL(CUpnpDevice* /*aDevice*/)
    {
    // No implementation required        
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::UPnPAVTimerCallback
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::UPnPAVTimerCallback(
    CUPnPAVTimer::TAVTimerType aType ) 
    {
    __LOG( "CUpnpAVControllerServer::UPnPAVTimerCallback" );


    if( aType == CUPnPAVTimer::ETimerServerShutdown )
        {
        ChangeState( EStateShutDown );
        CActiveScheduler::Stop();
        }
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::ConnectionLost
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::ConnectionLost( TBool /*aUserOriented*/ )
    {
    __LOG( "CUpnpAVControllerServer::ConnectionLost" );
    
    iShutdownTimeoutValue = 0; // Set shutdown timer value to 0, we want to
    // shut down the server immidiately after the last session has been
    // closed
    
    if( iState == EStateRunning && iDeviceRepository )
        {
        __LOG( "ConnectionLost - Server running" );
        
        iDeviceRepository->ConnectionLost();    

        CSession2* s;
        iSessionIter.SetToFirst(); 
        while ( ( s = iSessionIter++ ) != NULL )
            {
            CUpnpAVControllerSession* sess =
                static_cast<CUpnpAVControllerSession*>(s);
            if( sess )
                {
                sess->ConnectionLost();    
                }
            };  
        ChangeState( EStateShuttingDown );
        }
    else if( iState == EStateStartingServer )
        {
        __LOG( "ConnectionLost - Server starting" );
        
        ChangeState( EStateShuttingDown );
        }    

    // If don't have any clients connect to server and current WLAN connection
    // is lost, we want to shut down the server immidiately.
    if ( iSessionCount <= 0 )
        {
        if ( iServerTimer->IsActive() )
            {
            iServerTimer->Cancel();
            }
        iServerTimer->Start( iShutdownTimeoutValue );
        }
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::RunError
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
TInt CUpnpAVControllerServer::RunError( TInt aError )
    {
    __LOG2( "CUpnpAVControllerServer::RunError msg: %d err: %d",
        Message().Function(), aError );

    if ( aError == KErrBadDescriptor )
        {
        PanicClient( Message(), EAVControllerServerBadDescriptor );
        }
    else if ( !Message().IsNull() )
        {
        Message().Complete( aError );
        }
        
    // The leave will result in an early return from CServer::RunL(),
    // skipping the call to request another message. So do that now in order
    // to keep the server running.
    ReStart();
    // Handled the error fully
    return KErrNone;
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::PanicClient
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::PanicClient(const RMessage2& aMessage,
    TAVControllerServerPanic aPanic)
    {
    __LOG1( "CUpnpAVControllerServer::PanicClient %d", aPanic );
       
    aMessage.Panic( KAVControllerName, aPanic );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::PanicServer
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::PanicServer(TAVControllerServerPanic aPanic)
    {
    __LOG1( "CUpnpAVControllerServer::PanicServer %d", aPanic );
    
    User::Panic( KAVControllerName, aPanic );
    }


// --------------------------------------------------------------------------
// CUpnpAVControllerServer::ThreadFunctionL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::ThreadFunctionL()
    {
    __LOG( "CUpnpAVControllerServer::ThreadFunctionL" );
    
    // Construct active scheduler
    CActiveScheduler* activeScheduler = new (ELeave) CActiveScheduler;
    CleanupStack::PushL( activeScheduler );
    // Install active scheduler
    // We don't need to check whether an active scheduler is already
    // installed
    // as this is a new thread, so there won't be one
    CActiveScheduler::Install( activeScheduler );    
    // Construct our server        
    CUpnpAVControllerServer* server = CUpnpAVControllerServer::NewLC();
    
    RProcess::Rendezvous( KErrNone );                
    // Start handling requests
    CActiveScheduler::Start();      
             
    CleanupStack::PopAndDestroy( server );  
    CleanupStack::PopAndDestroy( activeScheduler );

    __LOG( "CUpnpAVControllerServer::ThreadFunctionL end" );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::ThreadFunction
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
TInt CUpnpAVControllerServer::ThreadFunction()
    {
    __LOG( "CUpnpAVControllerServer::ThreadFunction" );
    
    __UHEAP_MARK;
    
    User::RenameThread(KAVControllerThreadName);
    
    CTrapCleanup* cleanupStack = CTrapCleanup::New();
    if ( !(cleanupStack) )
        {
        PanicServer( EAVControllerServerCreateTrapCleanup );
        }

    TRAPD( err, ThreadFunctionL() );
    if ( err != KErrNone )
        {
        __LOG1( "ThreadFunction, creation failed: %d", err );
        //PanicServer( EAVControllerServerSrvCreateServer );
        }

    delete cleanupStack;
    cleanupStack = NULL;
       
    __UHEAP_MARKEND;

    __LOG1( "CUpnpAVControllerServer::ThreadFunction end %d", err );

    return err;
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::IncrementSessions
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::IncrementSessions() 
    {
    __LOG2( "CUpnpAVControllerServer::IncrementSessions, %d, %d", 
            iSessionCount, iState );
    
    iSessionCount++;
    if( iServerTimer->IsActive() )
        {
        iServerTimer->Cancel();
        }
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DecrementSessions
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::DecrementSessions()
    {
    __LOG2( "CUpnpAVControllerServer::DecrementSessions, %d, %d", 
            iSessionCount, iState );
    
    iSessionCount--;
    if( iState != EStateShutDown )
        {
        if ( iSessionCount <= 0 )
            {
            if( iServerTimer->IsActive() )
                {
                iServerTimer->Cancel();
                }
            iServerTimer->Start( iShutdownTimeoutValue );
            }
        }
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DeviceDiscoveredL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::DeviceDiscoveredL( CUpnpDevice& aDevice )
    {
    __LOG( "CUpnpAVControllerServer::DeviceDiscoveredL" );

    iDeviceRepository->AddDeviceL( aDevice );

    CUpnpAction* action = iAVControlPoint->CreateActionLC( 
            &aDevice, KConnectionManager, KGetProtocolInfo );

    iAVControlPoint->SendL( action ); // takes ownership
    CleanupStack::Pop( action );
    iDispatcher->RegisterL( action->SessionId(), *this );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DeviceDisappearedL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::DeviceDisappearedL( CUpnpDevice& aDevice )
    {
    __LOG( "CUpnpAVControllerServer::DeviceDisappearedL" );
    
    // Get a corresponding device from the device repository
    CUpnpAVDeviceExtended& tmp = iDeviceRepository->FindDeviceL(
        aDevice.Uuid() ); 
    
    // Let the clients know about the disappeared device
    CSession2* s;
    iSessionIter.SetToFirst(); 
    while ( ( s = iSessionIter++ ) != NULL )
        {
        CUpnpAVControllerSession* sess =
            static_cast<CUpnpAVControllerSession*>(s);
        if( sess )
            {
            sess->DeviceDisappearedL( tmp );    
            }
        };
    // Remove from the device repository
    TPtrC8 uuid( aDevice.Uuid() );
    iDeviceRepository->Remove( uuid );
    // Ensure that icon download is canceled
    iIconDownloader->CancelDownload( uuid );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DeviceDisappearedL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::DeviceDisappearedL( const TDesC8& aUuid )
    {
    __LOG( "CUpnpAVControllerServer::DeviceDisappearedL uid" );
    // Get a corresponding device from the device repository
    CUpnpAVDeviceExtended& tmp = iDeviceRepository->FindDeviceL(
        aUuid ); 
    
    // Let the clients know about the disappeared device
    CSession2* s;
    iSessionIter.SetToFirst(); 
    while ( ( s = iSessionIter++ ) != NULL )
        {
        CUpnpAVControllerSession* sess =
            static_cast<CUpnpAVControllerSession*>( s );
        if ( sess )
            {
            sess->DeviceDisappearedL( tmp );    
            }
        }       
    // Remove from the device repository
    iDeviceRepository->Remove( aUuid );
    // Ensure that icon download is canceled
    iIconDownloader->CancelDownload( aUuid );

    __LOG( "CUpnpAVControllerServer::DeviceDisappearedL uid End" );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::CmProtocolInfoResponse
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::CmProtocolInfoResponse( const TDesC8& aUuid,
    TInt aErr, const TDesC8& aSource,
    const TDesC8& aSink )
    {
    __LOG1( "CUpnpAVControllerServer::CmProtocolInfoResponse, \
aErr = %d", aErr );

    aErr = UPnPAVErrorHandler::ConvertToSymbianErrorCode( aErr,
        EUPnPConnectionManagerError );    

    if( aErr == KErrNone )
        {
        CUpnpAVDeviceExtended* dev = NULL;
        TRAPD( err, dev = &iDeviceRepository->AddProtocolInfoL(
            aUuid, aSource, aSink ) );
        
        if( err == KErrNone )    
            {
            // Device discovered and protocolinfo was retrieved successfully
            // Start icon download if icon url is defined
            TPtrC8 iconUrl( dev->IconUrl() );
            if ( iconUrl.Length() > 0 )
                {
                TRAP_IGNORE( iIconDownloader->StartDownloadL( dev->Uuid(), iconUrl ) );
                }
            CSession2* s;
            iSessionIter.SetToFirst(); 
            while ( ( s = iSessionIter++ ) != NULL )
                {
                CUpnpAVControllerSession* sess =
                    static_cast<CUpnpAVControllerSession*>(s);
                if( sess )
                    {
                    TRAP_IGNORE( sess->DeviceDiscoveredL( *dev ) );    
                    }
                };
            }
        else
            {
            // Could not add protocolinfo, it's invalid or corrupted
            // Device cannot be used
            HandleFailedProtocolInfoResponse( aUuid );          
            }
        }
    else
        {
        // A problem occured fetching protocolinfo
        // Device cannot be used
        HandleFailedProtocolInfoResponse( aUuid );
        }        
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::TransferDeviceIconFileToClientL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::TransferDeviceIconFileToClientL(
        const RMessage2& aMessage, TInt aSlot, const TDesC8& aDeviceUuid )
    {
    return iIconDownloader->TransferFileToClientL( aMessage, aSlot, aDeviceUuid );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::HandleFailedProtocolInfoResponse
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::HandleFailedProtocolInfoResponse(
    const TDesC8& aUuid )
    {
    __LOG( "CUpnpAVControllerServer::HandleFailedProtocolInfoResponse" );
    
    iDeviceRepository->Remove( aUuid );
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::ChangeState
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::ChangeState( TAVControllerServerState aState )
    {
    __LOG( "CUpnpAVControllerServer::ChangeState" );
    
    if( iState != aState )
        {
        __LOG2( "ChangeState: Changing state [%d] -> [%d]",
            iState, aState );
        iState = aState;
        }
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::ControlPoint
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
CUpnpAVControlPoint& CUpnpAVControllerServer::ControlPoint()
    {
    return *iAVControlPoint;
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::Dispatcher
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
CUPnPAVDispatcher& CUpnpAVControllerServer::Dispatcher()
    {
    return *iDispatcher;
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DeviceRepository
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
CUPnPDeviceRepository& CUpnpAVControllerServer::DeviceRepository()
    {
    return *iDeviceRepository;
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::IAP
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
TInt CUpnpAVControllerServer::IAP()
    {
    return iIAP;
    }

// --------------------------------------------------------------------------
// CUpnpAVControllerServer::DeviceIconDownloadedL
// See upnpavcontrollerserver.h
// --------------------------------------------------------------------------
void CUpnpAVControllerServer::DeviceIconDownloadedL( const TDesC8& aDeviceUuid,
        TInt aError )
    {
    __LOG( "CUpnpAVControllerServer::DeviceIconDownloadedL" );
    if ( aError == KErrNone )
        {
        // Get a corresponding device from the device repository
        CUpnpAVDeviceExtended& tmp = iDeviceRepository->FindDeviceL(
            aDeviceUuid );
        // Let the clients know about downloaded icon
        CSession2* s;
        iSessionIter.SetToFirst(); 
        while ( ( s = iSessionIter++ ) != NULL )
            {
            CUpnpAVControllerSession* sess =
                static_cast<CUpnpAVControllerSession*>( s );
            if ( sess )
                {
                sess->DeviceIconDownloadedL( tmp );
                }
            }
        }
    __LOG( "CUpnpAVControllerServer::DeviceIconDownloadedL End" );
    }

// ============================= LOCAL FUNCTIONS ============================

// --------------------------------------------------------------------------
// E32Main entry point.
// Returns: KErrNone
// --------------------------------------------------------------------------
TInt E32Main()
    {
    return CUpnpAVControllerServer::ThreadFunction();
    }

// End of File