upnp/upnpstack/controlpointbase/src/upnpcontrolpoint.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:12:20 +0200
changeset 0 f5a58ecadc66
permissions -rw-r--r--
Revision: 201003

/** @file
* Copyright (c) 2005-2006 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:  Declares ControlPoint class.
 *
*/


// INCLUDE FILES

#include <e32base.h>
#include <e32cons.h>
#include <e32std.h>
#include <in_sock.h>
#include <charconv.h>
#include <utf.h>

#include "upnpdispatcher.h"
#include "upnphttpmessage.h"
#include "upnpsoapmessage.h"
#include "upnpicon.h"
#include "upnpdevice.h"
#include "upnpstring.h"
#include "upnphttpmessagefactory.h"
#include "upnpsoapmessagefactory.h"
#include "upnpgenamessagefactory.h"
#include "upnpserviceinfo.h"
#include "upnpcontrolpoint.h"
#include "upnpcommonupnplits.h"
#include "upnpcons.h"
#include "upnpcpbhttpmessagecontroller.h"
#include "upnpcpbcurrenthttpclient.h"
#include "upnpcpbdescriptionagent.h"
#include "upnpcpbdiscoveryagent.h"
#include "upnpcpbdevicerepository.h"
#include "upnpcpstackrequestor.h"
#include "upnpcontenthandlerscontroller.h"
#include "upnpconnectionmanagernetworkeventprovider.h"
#include "upnpcpbinitialeventretryhandler.h"

#define KLogFile _L("UPnPCP.txt")
#include "upnpcustomlog.h"

using namespace UpnpHTTP;

static const TInt KDTargetDeviceTypesGranularity = 1;

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

// -----------------------------------------------------------------------------
// CUpnpControlPoint::CUpnpControlPoint
// C++ default constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CUpnpControlPoint::CUpnpControlPoint()
    : iPredefinedStackRequestor( NULL ), iPredefinedHttpRequestor( NULL )
    {
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::CUpnpControlPoint
// C++ constructor for internal, automated test cases use
// -----------------------------------------------------------------------------
//
EXPORT_C CUpnpControlPoint::CUpnpControlPoint(
    MUpnpCpStackRequestor& aStackRequestor, MUpnpCpHttpRequestor& aHttpRequestor )
    : iPredefinedStackRequestor( &aStackRequestor ),
      iPredefinedHttpRequestor( &aHttpRequestor )
    {
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::~CUpnpControlPoint
// C++ default destructor
// -----------------------------------------------------------------------------
//
EXPORT_C CUpnpControlPoint::~CUpnpControlPoint()
    {
    LOG_FUNC_NAME;

    delete iCpbHttpClient;

    iSubscribedServicesInfos.ResetAndDestroy();
    iActionList.ResetAndDestroy();
    
    if ( iTargetDeviceTypes )
        {
        iTargetDeviceTypes->Reset();
        delete iTargetDeviceTypes;
        }

    delete iDescriptionAgent;
    delete iDiscoveryAgent;

    delete iNetworkEventProvider;

    delete iSaxController;
    delete iDeviceRepository;
    delete iInitialEventRetry;
    LOGS("CUpnpControlPoint::~CUpnpControlPoint - END");
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::ConstructL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::ConstructL( const CDesC8Array& aTargetDeviceTypes )
    {
    iNetworkEventProvider = CUpnpConnectionManagerNetworkEventProvider::NewL( *this );

    iCpbHttpClient =
        CUpnpCpbCurrentHttpClient::NewL(
            *this, iPredefinedHttpRequestor, iPredefinedStackRequestor );
    iTargetDeviceTypes = new( ELeave ) CDesC8ArrayFlat( KDTargetDeviceTypesGranularity );

    for ( TInt i( 0 ); i < aTargetDeviceTypes.Count(); i++ )
        {
        iTargetDeviceTypes->AppendL( aTargetDeviceTypes[i]);
        }
    iDeviceRepository = CUpnpCpbDeviceRepository::NewL(*iTargetDeviceTypes);

    iSaxController = CUpnpContentHandlersController::NewL();
    iDiscoveryAgent = CUpnpCpbDiscoveryAgent::NewL( *iCpbHttpClient );
    iDescriptionAgent =
        CUpnpCpbDescriptionAgent::NewL(
            *this, *iCpbHttpClient, *iDeviceRepository );
    
    iInitialEventRetry = new( ELeave ) CUpnpCpbInitialEventRetryHandler( *this );
    
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::ConstructL
// Two-phased constructor
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::ConstructL( const TDesC8& aTargetDeviceType )
    {
    CDesC8ArrayFlat* targetDeviceTypes =
    new (ELeave) CDesC8ArrayFlat( KDTargetDeviceTypesGranularity );
    CleanupStack::PushL( targetDeviceTypes );
    targetDeviceTypes->AppendL( aTargetDeviceType );
    ConstructL( *targetDeviceTypes );
    CleanupStack::PopAndDestroy( targetDeviceTypes );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::SearchL
// Search intresting Device Types from network
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::SearchL( const TDesC8& aSearchString )
    {
    if( aSearchString.Length() == 0 )
        {
        User::Leave( KErrCorrupt );
        }
    iDiscoveryAgent->SearchL( aSearchString );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::SendL
// Send an action message.
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::SendL( CUpnpAction* aAction )
    {
    iCpbHttpClient->SendActionL( aAction );
    iActionList.AppendL( aAction );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::SendL
// Send HTTP message
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::SendL( CUpnpHttpMessage* aHttpMessage )
    {
    iCpbHttpClient->SendFileByPostL(aHttpMessage);
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::SendResponseMessageLD
// Send HTTP message and destroy it (leave safe)
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::SendResponseMessageLD( CUpnpHttpMessage* aHttpMessage )
    {
    CleanupStack::PushL( aHttpMessage );
    iCpbHttpClient->SendL( aHttpMessage );
    CleanupStack::PopAndDestroy( aHttpMessage );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::DeviceList
//
// -----------------------------------------------------------------------------
//
EXPORT_C const RPointerArray<CUpnpDevice>& CUpnpControlPoint::DeviceList() const
    {
    return iDeviceRepository->DiscoveredDeviceList();
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::SubscribeL
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::SubscribeL( CUpnpService* aService )
    {
    LOG_FUNC_NAME;

    if ( !aService )
        {
        return;
        }

    if( FindServiceInfoByService( aService ) )
        {
        return;
        }

    LOGS("CUpnpControlPoint::SubscribeL - Subscribing service");

    CUpnpServiceInfo* serviceInfo = CUpnpServiceInfo::NewLC( this, aService );
    iSubscribedServicesInfos.AppendL( serviceInfo );
    CleanupStack::Pop( serviceInfo );

    iCpbHttpClient->SendSubscribeL( serviceInfo );

    LOGS("CUpnpControlPoint::SubscribeL - end");

    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::UnsubscribeL
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::UnsubscribeL( const CUpnpService* aService )
    {
    UnsubscribeL( const_cast<CUpnpService*>( aService ) , ETrue );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::UnsubscribeL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::UnsubscribeL( CUpnpService* aService,
    TBool aSendUnsubscribeMessage )
    {
    LOG_FUNC_NAME;

    if ( !aService )
        {
        return;
        }

    CUpnpServiceInfo* subscribedServiceInfo =
            FindServiceInfoByService( aService );
    if ( !subscribedServiceInfo )
        {
        return;
        }

    LOGS("CUpnpControlPoint::UnsubscribeL - Unsubscribing service");

    RemoveFromSubscribedList( subscribedServiceInfo );

    if ( aSendUnsubscribeMessage )
        {
        CleanupStack::PushL( subscribedServiceInfo );
        iCpbHttpClient->SendUnsubscribeL( subscribedServiceInfo );
        CleanupStack::Pop( subscribedServiceInfo );
        }

    delete subscribedServiceInfo;

    LOGS("CUpnpControlPoint::UnsubscribeL - end");
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::ResubscribeL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::ResubscribeL( CUpnpServiceInfo* aServiceInfo )
    {
    iCpbHttpClient->SendResubscribeL( aServiceInfo );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::RemoveFromSubscribedList
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::RemoveFromSubscribedList(
    CUpnpServiceInfo* aServiceInfoToRemove )
    {
    const TInt idx = iSubscribedServicesInfos.Find( aServiceInfoToRemove );
    if ( KErrNotFound != idx )
        {
        iSubscribedServicesInfos.Remove( idx );
        }
    iSubscribedServicesInfos.GranularCompress();
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::DeviceFoundL
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::DeviceFoundL( CUpnpDevice& aDevice )
    {
    iDescriptionAgent->DeviceAliveNotificationL(&aDevice);
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::DeviceLostL
// Callback function - remove device
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::DeviceLostL( CUpnpDevice& aDevice )
    {
    LOG_FUNC_NAME;

    //device from ssdp
    CUpnpDevice* ssdpDevice =
        iDeviceRepository->RemoveIncomingDevice( aDevice.Uuid() );
    if ( ssdpDevice )
        {
        delete ssdpDevice;
        }
    CUpnpDevice* device = NULL;

    device = iDeviceRepository->FindDevice( aDevice.Uuid() );

    if ( !device )
        {
        return;
        }

    if ( aDevice.Expired() )
        {
        device->SetExpired( ETrue );
        if ( !AllDevicesExpired( device ) )
            {
            return;
            }
        }

    // always remove whole device tree
    if ( device->IsEmbeddDevice() )
        {
        CUpnpDevice* rootDevice = iDeviceRepository->FindRoot( device->Uuid() );
        // In case of error when root device is not found during discovery
        if ( rootDevice )
            {
            device = rootDevice;
            }
        }

    RemoveRootDeviceLD( device );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::AllDevicesExpired
//
// -----------------------------------------------------------------------------
//
TBool CUpnpControlPoint::AllDevicesExpired( CUpnpDevice* aDevice )
    {
    // notification about expiration of cache-control time of aDevice
    if ( aDevice->IsEmbeddDevice() ) // take root device
        {
        aDevice = iDeviceRepository->FindRoot( aDevice->Uuid() );
        }
    // if root device not expired then return
    if ( !aDevice || !aDevice->Expired() )
        {
        return EFalse;
        }
    RPointerArray<CUpnpDevice> devices;
    aDevice->GetAllDevices( devices ); // take all embedded devices
    for ( TInt k = 0; k < devices.Count(); k++ )
        {
        // if not all embedded devices expired then return
        if ( !devices[k]->Expired() )
            {
            devices.Close();
            return EFalse;
            }
        }
    devices.Close();
    return ETrue;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::Path
//
// -----------------------------------------------------------------------------
//
EXPORT_C const TDesC8& CUpnpControlPoint::Path()
    {
    return KPath();
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::MessageReceived
// Callback funtion - HTTP message received
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::MessageReceived( CUpnpHttpMessage* aHttpMessage )
    {
    HttpResponseReceived( aHttpMessage );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::MapHttpError
//
// -----------------------------------------------------------------------------
//
TInt CUpnpControlPoint::MapHttpError( TInt aError )
    {
    if ( aError >= EHttpBadRequest && aError < EHttpInternalServerError )
        {
        return KErrCouldNotConnect;
        }
    else if ( aError > EHttpInternalServerError )
        {
        return KErrServerBusy;
        }
    else
        {
        return KErrUnknown;
        }

    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::CheckEventKey
//
// -----------------------------------------------------------------------------
//
TInt CUpnpControlPoint::CheckEventKey( const TDesC8& aIncomingSeq,
    TUint32 aExistingSeq )
    {
    const TUint KMaxSeq = 2146583647;
    const TUint KMinSeq = 1;

    TUint IncomingSeq;
    TInt error = KErrNone;

    TLex8 lex(aIncomingSeq);
    lex.Mark();
    error = lex.Val( IncomingSeq );

    //--- check if SEQ is a number
    if ( !error )
        {
        lex.UnGetToMark();

        for ( TInt i(0); i < aIncomingSeq.Length(); i++ )
            {
            TChar character = lex.Get();
            if ( !(character.IsDigit() ) )
                {
                error = KErrGeneral;
                break;
                }
            }
        }

    //--- check SEQ incrementing/wrapping
    if ( !error )
        {
        // when initial event appears, don't check SEQ increment
        if ( (IncomingSeq == 0 ) && (aExistingSeq == 0 ) )
            return KErrNone;

        if ( aExistingSeq < KMaxSeq )
            {
            aExistingSeq++;
            }
        else
            {
            aExistingSeq = KMinSeq;
            }

        // if 'incoming SEQ' == 'incremented existing SEQ' -> OK
        if ( IncomingSeq == aExistingSeq )
            {
            error = KErrNone;
            }
        else
            {
            error = KErrCancel;
            }
        }

    return error;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::ThrowErrorL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::SendErrorResponseL( CUpnpHttpMessage* aHttpMessage,
    THttpStatusCode aCode )
    {
    CUpnpHttpMessage* msg = RUpnpHttpMessageFactory::HttpResponseErrorL(
        aHttpMessage, aCode );
    SendResponseMessageLD( msg );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::SubscriptionResponseReceivedL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::SubscriptionResponseReceivedL(
    CUpnpHttpMessage& aHttpMessage )
    {
    LOG_FUNC_NAME;
    CUpnpGenaMessage* genaMsg =
            reinterpret_cast <CUpnpGenaMessage*> ( &aHttpMessage );

    CUpnpServiceInfo* tmpServiceInfo = FindServiceInfoByGenaMessage( genaMsg );
    if ( !tmpServiceInfo )
        {
        return;
        }

    tmpServiceInfo->SetSidL( genaMsg->Sid() );
    tmpServiceInfo->StartTimerL( genaMsg->Timeout() );
    if(iDeviceRepository->MatchTargetDevice(_L8("*")))
        {
        aHttpMessage.SetType(ESubscription);
        aHttpMessage.SetDestinationPathL(tmpServiceInfo->Service()->SubscriptionUrl());
        TRAP_IGNORE( HttpResponseReceivedL( &aHttpMessage ) );
        }

    LOGS("CUpnpControlPoint::SubscRespRcvdL - end");
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::HandlePostponedInitialEventL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::HandlePostponedInitialEventL( CUpnpGenaMessage& aGenaMsg )
    {
    CUpnpServiceInfo* serviceInfo = FindServiceInfoBySid(
            iSubscribedServicesInfos, aGenaMsg.Sid() );
    if ( serviceInfo )
        {
        if(iDeviceRepository->MatchTargetDevice(_L8("*")))
            {
            aGenaMsg.SetDestinationPathL(serviceInfo->Service()->SubscriptionUrl());
            TRAP_IGNORE( HttpResponseReceivedL( &aGenaMsg) );
            }
        ParseEventUpdateStateVariablesL( aGenaMsg, *serviceInfo );        
        SendResponseMessageLD( RUpnpHttpMessageFactory::HttpResponseOkL(
                &aGenaMsg ) );
        }
    else
        {
        SendErrorResponseL( &aGenaMsg, EHttpPreconditionFailed );
        }
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::UnSubscriptionResponseReceived
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::UnSubscriptionResponseReceived()
    {
    LOG_FUNC_NAME;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::NotifyReceivedL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::NotifyReceivedL( CUpnpHttpMessage& aHttpMessage )
    {
    LOGS( "CUpnpControlPoint::NotifyReceivedL - start" );
    CUpnpGenaMessage* genaMsg =
            reinterpret_cast<CUpnpGenaMessage*> ( &aHttpMessage );
    CleanupStack::PushL(genaMsg);

    THttpStatusCode code = ValidateEventResolveHttpResponseCode( *genaMsg );
    if ( code != EHttp200Ok )
        {
        //--- If some of conditions are not fulfilled, send error
        SendErrorResponseL(genaMsg, code);
        CleanupStack::PopAndDestroy(genaMsg);
        LOGS( "CUpnpControlPoint::NotifyReceivedL - end" );
        return;
        }
    //--- checking if genaMsg SID is the same like the one in subscribed service.
    CUpnpServiceInfo* subscribedServiceInfo = FindServiceInfoBySid(
            iSubscribedServicesInfos, genaMsg->Sid());

    if ( subscribedServiceInfo )
        {
        //===== Checking validity of SEQ header
        TInt seqError = KErrNone;
        seqError = CheckEventKey( genaMsg->Seq(), subscribedServiceInfo->Seq() );
        if ( seqError )
            {
            if ( seqError == KErrCancel )
                {
                //------ if SEQ's order invalid
                //-> e.g 0,1,2 and then 1 -> Unsubscribe/Subscribe
                ResubscribeL( *subscribedServiceInfo );
                }
            else
                {
                LOGS( "CUpnpControlPoint::NotifyReceivedL - SEQ INAVLID" );
                SendErrorResponseL( genaMsg, EHttpBadRequest );
                User::Leave(seqError);
                }
            }
        else
            {
            if(iDeviceRepository->MatchTargetDevice(_L8("*")))
                {
                genaMsg->SetDestinationPathL(subscribedServiceInfo->Service()->SubscriptionUrl());
                TRAP_IGNORE( HttpResponseReceivedL( genaMsg) );
                }
            ParseEventUpdateStateVariablesL( *genaMsg, *subscribedServiceInfo );
            SendResponseMessageLD(RUpnpHttpMessageFactory::HttpResponseOkL( genaMsg ));
            LOGS( "CUpnpControlPoint::NotifyReceivedL - send OK" );
            }        
        CleanupStack::PopAndDestroy( genaMsg );
        
        }
    else
        {
        TInt seq;
        TLex8 lex( genaMsg->Seq() );
        TInt error = lex.Val(seq);
        
        if ( !error && seq == 0 )
            {
            CleanupStack::Pop( genaMsg );
            //ownership is passed through
            iInitialEventRetry->AddL( genaMsg );        
            }
        else
            {
            SendErrorResponseL( genaMsg, EHttpPreconditionFailed );            
            CleanupStack::PopAndDestroy( genaMsg );
            }
        }
    
    }


// -----------------------------------------------------------------------------
// CUpnpControlPoint::Device
// This function returns a pointer to device identified by UUID.
// (other items were commented in a header).es
// -----------------------------------------------------------------------------
//
CUpnpServiceInfo* CUpnpControlPoint::FindServiceInfoBySid( RPointerArray<CUpnpServiceInfo>& aInfos,
        const TDesC8& aSid )
    {
    for ( TInt i=0; i < aInfos.Count(); i++ )
        {
        CUpnpServiceInfo* subscribedServiceInfo = aInfos[i];             
        if ( (subscribedServiceInfo->Sid().Length()> 0 )
         && (subscribedServiceInfo->Sid() == aSid ) )
            {
            return subscribedServiceInfo;
            }
        }
    return NULL;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::ResubscribeL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::ResubscribeL( CUpnpServiceInfo& aInfo )
    {
    //------ if SEQ's order invalid
    //-> e.g 0,1,2 and then 1 -> Unsubscribe/Subscribe
    CUpnpService* service =
        aInfo.Service(); // remember the service

    UnsubscribeL( service );
    // after unsubscribing -> subscribe again
    SubscribeL( service );

    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::ParseEventUpdateStateVariablesL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::ParseEventUpdateStateVariablesL(
        CUpnpGenaMessage& aGenaMsg, CUpnpServiceInfo& aInfo )
    {
    TInt parsingError = KErrNone;
        TRAP( parsingError, iSaxController->AttachL(
                aGenaMsg.Body(), *( aInfo.Service() ) ) );
    if ( parsingError )
        {
        LOGS( "CUpnpControlPoint::NotifyReceivedL - "
                "parsing gena or parsing SEQ - FAILED" );
        SendErrorResponseL( &aGenaMsg, EHttpBadRequest );
        User::Leave( parsingError );
        }

    // if SEQ ok -> put the value to the service
    TInt seq;
    TLex8 lex( aGenaMsg.Seq() );
    TInt error = lex.Val( seq );
    // error ignored, it is fully checked in CheckEventKey()

    aInfo.SetSeq( seq );
    StateUpdated( aInfo.Service() );

    }

 // -----------------------------------------------------------------------------
// CUpnpControlPoint::ValidateEventResolveHttpResponseCode
//
// -----------------------------------------------------------------------------
//
THttpStatusCode CUpnpControlPoint::ValidateEventResolveHttpResponseCode(
        CUpnpGenaMessage& aGenaMsg )

    {
    THttpStatusCode code = EHttp200Ok;
    //--- NOTIFY message syntax - checking if headers: NT and NTS exists
    
    if ( aGenaMsg.Method() != UpnpGENA::KGenaNotify() 
            || aGenaMsg.Nt() == KNoHeader 
            || aGenaMsg.Nts() == KNoHeader )
        {
        // headers NT or NTS are missing
        code = EHttpBadRequest;
        LOGS( "CUpnpControlPoint::NotifyReceivedL - bad request" );
        }

    //--- NOTIFY message syntax
    //- checking if headers: NT and NTS has proper structure [name: value]
    else if (aGenaMsg.Nt() != UpnpGENA::KDefaultNt || aGenaMsg.Nts()
            != UpnpGENA::KDefaultNts)
        {
        // headers NT or NTS are invalid
        code = EHttpPreconditionFailed;
        LOGS( "CUpnpControlPoint::NotifyReceivedL - headers NT or NTS are invalid" );
        }
    return code;
    }


// -----------------------------------------------------------------------------
// CUpnpControlPoint::Device
// This function returns a pointer to device identified by UUID.
// (other items were commented in a header).es
// -----------------------------------------------------------------------------
//
EXPORT_C const CUpnpDevice* CUpnpControlPoint::Device(const TDesC8& aUuid)
    {
    RPointerArray<CUpnpDevice> devices = DeviceList();
    for( TInt i(0); i < devices.Count(); i++)
        {
        if(aUuid.Compare( devices[i]->Uuid() ) == 0)
            {
            return devices[i];
            }
        }
    return NULL;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::AddressChangedL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::AddressChangedL()
    {
    LOG_FUNC_NAME;
    TInt i(0);
    RPointerArray<CUpnpDevice> devices = iDeviceRepository->DiscoveredDeviceList();
    RPointerArray<CUpnpDevice> rootDevices;
    CleanupClosePushL(rootDevices);
    for( i = 0; i < devices.Count(); i++)
        {
        if(!devices[i]->IsEmbeddDevice())
            {
            rootDevices.AppendL(devices[i]);
            }
        }
    devices = iDeviceRepository->UnneddedDeviceList();
    for( i = 0; i < devices.Count(); i++)
        {
        if(!devices[i]->IsEmbeddDevice())
            {
            rootDevices.AppendL(devices[i]);
            }
        }
    devices = iDeviceRepository->UninterestingDeviceList();
    for( i = 0; i < devices.Count(); i++)
        {
        if(!devices[i]->IsEmbeddDevice())
            {
            rootDevices.AppendL(devices[i]);
            }
        }
    devices = iDeviceRepository->IncompliteDeviceList();
    for( i = 0; i < devices.Count(); i++)
        {
        if(!devices[i]->IsEmbeddDevice())
            {
            rootDevices.AppendL(devices[i]);
            }
        }

    for( i = 0; i < rootDevices.Count(); i++)
        {
        RemoveRootDeviceLD( rootDevices[i] );
        }
    CleanupStack::PopAndDestroy(&rootDevices);

    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::GiveAddressL
//
// -----------------------------------------------------------------------------
//
TInetAddr CUpnpControlPoint::GiveAddressL( const TDesC8& aUrl )
    {
    TInetAddr result= INET_ADDR(0,0,0,0);
    result.SetPort( 0 );
    TInt colonPos = aUrl.Find( KColon() ) ;
    if ( colonPos != KErrNotFound )
        {
        TPtrC8 addressStr = aUrl.Left( colonPos );
        HBufC* buffer = HBufC::NewL( addressStr.Length() );
        TPtr bufferPtr(buffer->Des() );
        bufferPtr.Copy( addressStr );
        result.Input( *buffer );
        delete buffer;
        const TDesC8& portStr = aUrl.Mid( colonPos + 1 );
        TLex8 lexer(portStr);
        TInt port(0);
        lexer.Val( port );
        result.SetPort( port );
        }
    else
        {
        HBufC* buffer = HBufC::NewL( aUrl.Length() );
        TPtr bufferPtr(buffer->Des() );
        bufferPtr.Copy( aUrl );
        result.Input( *buffer );
        delete buffer;
        }
    return result;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::RemoveRootDeviceLD
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::RemoveRootDeviceLD( CUpnpDevice* aDevice )
    {
    TBool isDiscovered = EFalse;

    iCpbHttpClient->StopIgnoringL( aDevice );

    RemoveActionsL( aDevice );
    RemoveServicesL( aDevice );

    //find all children of the device to be removed
    RPointerArray<CUpnpDevice> devices;
    aDevice->GetAllDevices( devices );
    CleanupClosePushL( devices );

    for ( TInt k = 0; k < devices.Count(); k++ )
        {
        RemoveActionsL( devices[k] );
        isDiscovered
                = iDeviceRepository->IsDiscoveredDevice( devices[k]->Uuid() );
        iDeviceRepository->RemoveDevice( devices[k] );
        if ( isDiscovered )
            {
            DeviceDisappeared( devices[k] );
            }
        RemoveServicesL( devices[k] );
        }

    CleanupStack::PopAndDestroy( &devices );

    iActionList.Compress();
    isDiscovered = iDeviceRepository->IsDiscoveredDevice( aDevice->Uuid() );
    iDeviceRepository->RemoveDevice( aDevice );
    if ( isDiscovered )
        {
        DeviceDisappeared( aDevice );
        }

    delete aDevice;
    aDevice = NULL;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::RemoveActionsL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::RemoveActionsL( CUpnpDevice* aDevice )
    {
    for ( TInt i = 0; i < iActionList.Count(); ++i )
        {
        if( ( iActionList[i]->Service().Device().Uuid()).Compare(
            aDevice->Uuid() ) == 0 )
            {
            CUpnpAction* action = iActionList[i];
            
            CUpnpSoapMessage* errorMsg =
                    RUpnpSoapMessageFactory::SoapResponseL( action,
                        EActionFailed );

            CleanupStack::PushL( errorMsg );
            iSaxController->UpdateActionWithErrorResponseL( errorMsg, action );
            ActionResponseReceived( action );
            iActionList.Remove( i );
            delete action;
            CleanupStack::PopAndDestroy( errorMsg );
            //as a action is removed from the list the
            //index is kept as same for the next loop.
            --i;
            }
        }
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::RemoveServicesL
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::RemoveServicesL( CUpnpDevice* aDevice )
    {
    RPointerArray<CUpnpService>& services = aDevice->ServiceList();
    for ( TInt j = 0; j < services.Count(); j++ )
        {
        UnsubscribeL( services[j], EFalse );
        }
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::FindServiceInfoByService
//
// -----------------------------------------------------------------------------
//
CUpnpServiceInfo* CUpnpControlPoint::FindServiceInfoByService(
    CUpnpService* aService )
    {
    for ( TInt i=0; i < iSubscribedServicesInfos.Count() ; i++ )
        {
        if ( iSubscribedServicesInfos[i]->Service() == aService )
            {
            return iSubscribedServicesInfos[i];
            }
        }
    return NULL;
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::FindServiceInfoByHttpMessage
//
// -----------------------------------------------------------------------------
//
CUpnpServiceInfo* CUpnpControlPoint::FindServiceInfoByGenaMessage(
    CUpnpGenaMessage* aGenaMsg )
    {
    for ( TInt i=0; i < iSubscribedServicesInfos.Count() ; i++ )
        {
        if ( iSubscribedServicesInfos[i]->SessionId()
                == aGenaMsg->SessionId() )
            {
            return iSubscribedServicesInfos[i];
            }
        }
    return NULL;
    }

void CUpnpControlPoint::ProcessDeviceMessageL( CUpnpHttpMessage* aHttpMessage )
    {
    iDescriptionAgent->ProcessDeviceMessageL( aHttpMessage );
    }

void CUpnpControlPoint::ProcessServiceMessageL( CUpnpHttpMessage* aHttpMessage )
    {
    iDescriptionAgent->ProcessServiceMessageL( aHttpMessage );
    }

void CUpnpControlPoint::ProcessActionMessageL( CUpnpHttpMessage* aHttpMessage )
    {
    
    TInt idx(0);
    // Match request action
    for ( ; idx < iActionList.Count() && iActionList[idx]->SessionId()
            != aHttpMessage->SessionId(); idx++ )
        {
        }
    if ( idx == iActionList.Count() )
        {
        return;
        }

    CUpnpAction* tmpAction = iActionList[idx];

     
    TInt error(KErrNone);
    switch ( aHttpMessage->Error() )
        {
        case EHttp200Ok:
            {
            TRAP( error,
                iSaxController->UpdateActionWithOKResponseL(
                            static_cast<CUpnpSoapMessage*>(aHttpMessage), tmpAction );
            );
            }
            break;
        case EHttpInternalServerError:
            {
            TRAP( error,
                iSaxController->UpdateActionWithErrorResponseL(
                            static_cast<CUpnpSoapMessage*>(aHttpMessage), tmpAction );
            );
            break;
            }
        default:
            {
            if ( aHttpMessage->InternalError() )
                {
                tmpAction->SetError( aHttpMessage->InternalError() );
                }
            else
                {
                tmpAction->SetError( MapHttpError( aHttpMessage->Error() ) );
                }
            break;
            }
        }
    if ( KErrNone != error )
        {
        tmpAction->SetError( error );
        }
    
    ActionResponseReceived( tmpAction );
    delete tmpAction;
    iActionList.Remove( idx );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::StateUpdated
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::StateUpdated( CUpnpService* aService )
    {
    TRAP_IGNORE( StateUpdatedL( aService ) );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::DeviceDiscovered
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::DeviceDiscovered( CUpnpDevice* aDevice )
    {
    TRAP_IGNORE( DeviceDiscoveredL( aDevice ) );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::DeviceDisappeared
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::DeviceDisappeared( CUpnpDevice* aDevice )
    {
    TRAP_IGNORE( DeviceDisappearedL( aDevice ) );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::ActionResponseReceived
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::ActionResponseReceived( CUpnpAction* aAction )
    {
    TRAP_IGNORE( ActionResponseReceivedL( aAction ) );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::HttpResponseReceived
//
// -----------------------------------------------------------------------------
//
void CUpnpControlPoint::HttpResponseReceived( CUpnpHttpMessage* aMessage )
    {
    TRAP_IGNORE( HttpResponseReceivedL( aMessage ) );
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::EnableRadaDeviceL
//
// -----------------------------------------------------------------------------
//
#ifdef RD_UPNP_REMOTE_ACCESS
EXPORT_C void CUpnpControlPoint::EnableRadaDeviceL( TRequestStatus& aStatus )
#else
EXPORT_C void CUpnpControlPoint::EnableRadaDeviceL( TRequestStatus& /*aStatus*/ )
#endif
    {
    #ifdef RD_UPNP_REMOTE_ACCESS
    iDiscoveryAgent->EnableRadaDeviceL( aStatus );
    #endif
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::EnableRadaDeviceL
//
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CUpnpControlPoint::EnableRadaDeviceL()
    {
    #ifdef RD_UPNP_REMOTE_ACCESS
    return iDiscoveryAgent->EnableRadaDeviceL();
    #else
    return KErrNotSupported;
    #endif
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::DisableRadaDeviceL
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::DisableRadaDeviceL()
    {
    #ifdef RD_UPNP_REMOTE_ACCESS
    iDiscoveryAgent->DisableRadaDeviceL();
    #endif
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::StartIPFilteringL
//
// -----------------------------------------------------------------------------
//
#ifdef RD_UPNP_REMOTE_ACCESS
EXPORT_C void CUpnpControlPoint::StartIPFilteringL( TFilteringMode aMode )
#else
EXPORT_C void CUpnpControlPoint::StartIPFilteringL( TFilteringMode /*aMode*/ )
#endif
    {
    #ifdef RD_UPNP_REMOTE_ACCESS
    switch( aMode )
        {
        case EBoth:
            {
            iCpbHttpClient->StartIPFilteringL();
            iDiscoveryAgent->StartIPFilteringL();
            break;
            }
        case ERada:
            {
            iDiscoveryAgent->StartIPFilteringL();
            break;
            }
        case EControlPoint:
            {
            iCpbHttpClient->StartIPFilteringL();
            break;
            }
        default:
            {
            User::Leave( KErrNotSupported );
            break;
            }
        }
    #endif
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::StopIPFilteringL
//
// -----------------------------------------------------------------------------
//
#ifdef RD_UPNP_REMOTE_ACCESS
EXPORT_C void CUpnpControlPoint::StopIPFilteringL( TFilteringMode aMode )
#else
EXPORT_C void CUpnpControlPoint::StopIPFilteringL( TFilteringMode /*aMode*/ )
#endif
    {
    #ifdef RD_UPNP_REMOTE_ACCESS
    switch( aMode )
        {
        case EBoth:
            {
            iCpbHttpClient->StopIPFiltering();
            iDiscoveryAgent->StopIPFiltering();
            break;
            }
        case ERada:
            {
            iDiscoveryAgent->StopIPFiltering();
            break;
            }
        case EControlPoint:
            {
            iCpbHttpClient->StopIPFiltering();
            break;
            }
        default:
            {
            User::Leave( KErrNotSupported );
            break;
            }
        }
    #endif
    }

// -----------------------------------------------------------------------------
// CUpnpControlPoint::NetworkEvent
// -----------------------------------------------------------------------------
//
EXPORT_C void CUpnpControlPoint::NetworkEvent( CUpnpNetworkEventBase* aEvent )
    {
    LOG_FUNC_NAME;

    switch ( aEvent->Type() )
        {
        case EWlanLostEvent:
            {
            iCpbHttpClient->WlanLostOccurs();
            }
            break;

        case EAddressChangeEvent:
            {         
            TRAP_IGNORE( iCpbHttpClient->AddressChangedL(); AddressChangedL() );
            }
            break;
        }
    }

//  End of File