upnp/upnpstack/controlpointbase/src/upnpcpbcurrenthttpclient.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:  CUpnpCpbCurrentHttpClient
 *
*/

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

#include "upnpcpstackrequestor.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 "upnpcpbhttpmessagecontroller.h"
#include "upnpcpbcurrenthttpclient.h"
#include "upnpcontrolpoint.h"
#include "upnpcommonupnplits.h"
#include "upnpcpbdevicedescription.h"
#include "upnpdevicedescriptionhttptransaction.h"
#include "upnpservicedescriptionhttptransaction.h"
#include "upnpsoapactionhttptransaction.h"
#include "upnpservicesubscriptionhttptransaction.h"
#include "upnpserviceunsubscriptionhttptransaction.h"
#include "upnpcphttprequestorimpl.h"
#include "upnpcpstackrequestorimpl.h"
#include "upnpfilesender.h"

#define KLogFile _L("UPnPControlPoint.txt")
#include <upnpcustomlog.h>

using namespace UpnpHTTP;

static const TInt KMessageTimeout( 10000000 );
static const TInt KActionTimeout( 35000000 );

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

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::CUpnpCurrentHttpClient
// C++ default constructor
// -----------------------------------------------------------------------------
//
CUpnpCpbCurrentHttpClient::CUpnpCpbCurrentHttpClient( CUpnpControlPoint& aControlPoint,
        MUpnpCpHttpRequestor* aHttpRequestor, MUpnpCpStackRequestor* aStackRequestor )
    : iControlPoint( aControlPoint ),
    iHttpRequestor( aHttpRequestor ), iStackRequestor( aStackRequestor )
    {
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::~CUpnpCpbCurrentHttpClient
// Destructor
// -----------------------------------------------------------------------------
//
CUpnpCpbCurrentHttpClient::~CUpnpCpbCurrentHttpClient()
    {
    if ( iStackRequestor )
        {
        iStackRequestor->RemoveCustomer( *this );
        }
    iPendingHttpMessages.ResetAndDestroy();
    iPendingTransactions.ResetAndDestroy();
    delete iUserAgent;
    delete iHttpRequestorDefaultImpl;
    delete iStackRequestorDefaultImpl;
    delete iFileSender;
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::NewL
//
// -----------------------------------------------------------------------------
//
CUpnpCpbCurrentHttpClient* CUpnpCpbCurrentHttpClient::NewL(
    CUpnpControlPoint& aControlPoint,
    MUpnpCpHttpRequestor* aHttpRequestor, MUpnpCpStackRequestor* aStackRequestor)
    {
    LOG_FUNC_NAME;
    CUpnpCpbCurrentHttpClient* self =
        new (ELeave) CUpnpCpbCurrentHttpClient( aControlPoint, aHttpRequestor, aStackRequestor );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::ConstructL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::ConstructL()
    {
    iFileSender = CUpnpFileSender::NewL( iControlPoint );
    
    if ( !iHttpRequestor )
        {
        iHttpRequestorDefaultImpl = CUpnpCpHttpRequestorImpl::NewL();
        iHttpRequestor = iHttpRequestorDefaultImpl;
        }
    iHttpRequestor->InitialiseL( *this, CUpnpSettings::GetIapL() );

    if ( !iStackRequestor )
        {
        iStackRequestorDefaultImpl = CUpnpCpStackRequestorImpl::NewL( iControlPoint );
        iStackRequestor = iStackRequestorDefaultImpl;
        }
    iStackRequestor->AddCustomerL( *this );
    ASSERT( iHttpRequestor && iStackRequestor ); //ensure correct initialisation
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SendActionL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SendActionL( CUpnpAction* aAction )
    {
    if( !aAction )
        {
        User::Leave( KErrArgument );
        }

    CUpnpHttpMessage* msg = RUpnpSoapMessageFactory::SoapRequestL( aAction );
    CleanupStack::PushL( msg );

    // 7.2.32.1 UPnP action requests (sent by a control point) must include a
    // DLNA-CP-version in a USER-AGENT HTTP header value.
    if ( !iUserAgent )
        {
        HBufC8* userAgent = CUpnpSettings::GetUserAgentL();
        CleanupStack::PushL( userAgent );

        iUserAgent = HBufC8::NewL( userAgent->Length() );
        iUserAgent->Des().Append( *userAgent );

        CleanupStack::PopAndDestroy( userAgent );
        }

    msg->AddPairL( UpnpHTTP::KHdrUserAgent, *iUserAgent );

    msg->SetTcpTimeout( KActionTimeout );
    
    CleanupStack::Pop( msg );//ownership passed to Transaction and is safe
    CUpnpHttpTransaction* soapTransaction = 
         CUpnpSoapActionHttpTransaction::NewLC( msg, aAction->SessionId(), iControlPoint );
                    
    iPendingTransactions.AppendL( soapTransaction );
    CleanupStack::Pop( soapTransaction );
    iHttpRequestor->SendL( *soapTransaction );
    
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SendSubscribeL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SendSubscribeL( CUpnpServiceInfo* aServiceInfo )
    {
    const TDesC8& path = Path();

    TInetAddr addr = iStackRequestor->HttpServerAddress();
    HBufC8* longPath = aServiceInfo->ConstructSubscribtionPathLC( path , addr ); 
    CUpnpGenaMessage* gena = aServiceInfo->CreateSubscriptionMessageL(
                                   *longPath,
                                   ESubscription );
    
    gena->SetTcpTimeout( KMessageTimeout );
    CUpnpServiceSubscriptionHttpTransaction* transaction =
        CUpnpServiceSubscriptionHttpTransaction::NewLC( gena, iControlPoint );
    iPendingTransactions.AppendL( transaction );
    CleanupStack::Pop( transaction );
    iHttpRequestor->SendL( *transaction );
    CleanupStack::PopAndDestroy( longPath );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SendUnsubscribeL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SendUnsubscribeL( CUpnpServiceInfo* aServiceInfo )
    {
    if ( aServiceInfo->Sid() != KNullDesC8 ) 
        {
        CUpnpGenaMessage* gena = aServiceInfo->CreateSubscriptionMessageL( EUnSubscription );
        gena->SetTcpTimeout( KMessageTimeout );
        CUpnpServiceUnsubscriptionHttpTransaction* transaction = 
            CUpnpServiceUnsubscriptionHttpTransaction::NewLC( gena, iControlPoint) ;
        iPendingTransactions.AppendL( transaction );
        CleanupStack::Pop( transaction );
        iHttpRequestor->SendL( *transaction );
        }
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SendResubscribeL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SendResubscribeL( CUpnpServiceInfo* aServiceInfo )
    {
    CUpnpGenaMessage* gena = aServiceInfo->CreateSubscriptionMessageL( EResubscription );
    gena->SetTcpTimeout( KMessageTimeout );
    CUpnpServiceSubscriptionHttpTransaction* transaction =
         CUpnpServiceSubscriptionHttpTransaction::NewLC( gena, iControlPoint );
    iPendingTransactions.AppendL( transaction );
    CleanupStack::Pop( transaction );
    iHttpRequestor->SendL( *transaction );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::GetServiceDescriptionL
//
// -----------------------------------------------------------------------------
//
TInt CUpnpCpbCurrentHttpClient::GetServiceDescriptionL( CUpnpDevice* aDevice,
    const TDesC8& aUrl )
    {
    CUpnpHttpMessage* result( NULL );
    TPtrC8 urlBase( aDevice->UrlBase() );

    if ( aUrl.Find( KHttp ) == 0 )
        {
        result = RUpnpHttpMessageFactory::HttpGetL( aUrl );
        }
    else
        {
        TInetAddr addr = aDevice->Address();
        if ( urlBase.Length() > 0 )
            {
            HBufC8* url = aDevice->ConcatWithUrlBaseL( aUrl );
            CleanupStack::PushL( url );

            if ( url->Find( KHttp ) )
                {
                result = RUpnpHttpMessageFactory::HttpGetL( addr, *url,
                    KNullDesC8 );
                }
            else
                {
                result = RUpnpHttpMessageFactory::HttpGetL( *url );
                }

            CleanupStack::PopAndDestroy( url );
            }
        else
            {
            result = RUpnpHttpMessageFactory::HttpGetL( addr,
                aDevice->DescriptionUrlPath(), aUrl );
            }
        }
    result->SetTcpTimeout( KMessageTimeout );

    CUpnpServiceDescriptionHttpTransaction* transaction =
        CUpnpServiceDescriptionHttpTransaction::NewLC( result, iControlPoint );

    iPendingTransactions.AppendL( transaction );
    CleanupStack::Pop( transaction );
    iHttpRequestor->SendL( *transaction );
    return result->SessionId();
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::GetDeviceDescriptionL
//
// -----------------------------------------------------------------------------
//
TInt CUpnpCpbCurrentHttpClient::GetDeviceDescriptionL( CUpnpDevice* aDevice )
    {
    TInetAddr addr = aDevice->DescriptionUrlAddressL();
    addr.SetPort( aDevice->DescriptionUrlPort() );

    CUpnpHttpMessage* message = RUpnpHttpMessageFactory::HttpGetL( addr,
        aDevice->DescriptionUrlPath() );
    message->SetTcpTimeout( KMessageTimeout );

    CUpnpDeviceDescriptionHttpTransaction* transaction =
        CUpnpDeviceDescriptionHttpTransaction::NewLC( message, iControlPoint );

    iPendingTransactions.AppendL( transaction );
    CleanupStack::Pop( transaction );
    iHttpRequestor->SendL( *transaction );

    return message->SessionId();
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::MessageReceivedLD
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::MessageReceivedLD( CUpnpHttpMessage* aHttpMessage )
    {
    if ( !aHttpMessage )
        {
        User::Leave( KErrArgument );
        }
    // match arrived response to pending request

    TIdentityRelation<CUpnpHttpMessage> matcher( CUpnpHttpMessage::SessionIdMatch );
    TInt idx = iPendingHttpMessages.Find ( aHttpMessage, matcher );

    CleanupStack::PushL( aHttpMessage );

    if ( aHttpMessage->IsGena() )
        {
        CleanupStack::Pop( aHttpMessage );
        iControlPoint.NotifyReceivedL( *aHttpMessage );
        }
    else
        {
        iControlPoint.MessageReceived( aHttpMessage );
        iPendingHttpMessages.Compress();
        CleanupStack::PopAndDestroy( aHttpMessage );
        }
    }

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

// ----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::StopIgnoringL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::StopIgnoringL( CUpnpDevice* aDevice )
    {
    iStackRequestor->StopIgnoringL( aDevice->Uuid() );
    StopIgnoringEmbeddedL( aDevice );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::StopIgnoringEmbeddedL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::StopIgnoringEmbeddedL( CUpnpDevice* aRoot )
    {
    RPointerArray<CUpnpDevice> devicesAll;
    aRoot->GetAllDevices( devicesAll );
    CleanupClosePushL( devicesAll );
    for ( TInt k = 0; k < devicesAll.Count(); k++ )
        {
        iStackRequestor->StopIgnoringL( devicesAll[k]->Uuid() );
        }
    CleanupStack::PopAndDestroy( &devicesAll );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::StopIgnoringUuidL
// Send stop ignoring message to MH
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::StopIgnoringUuidL( const TDesC8& aUuids )
    {
    iStackRequestor->StopIgnoringL( aUuids );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::StartIPFilteringL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::StartIPFilteringL()
    {
    iStackRequestor->StartIPFilteringL();
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::StopIPFiltering
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::StopIPFiltering()
    {
    iStackRequestor->StopIPFiltering();
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SendL
// Send response HTTP message
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SendL( CUpnpHttpMessage* aHttpMessage )
    {
    const TInt KUnused(0);
    iStackRequestor->SendMessageL( aHttpMessage, *this, KUnused );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SendFileByPostL
// Send HTTP message
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SendFileByPostL( CUpnpHttpMessage* aHttpMessage )
    {
    if ( !aHttpMessage )
        {
        User::Leave( KErrArgument );
        }
    iFileSender->SendL( *aHttpMessage );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SearchL
// Sends a SSDP Search with 8-bit search string.
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SearchL( const TDesC8& aSearchString )
    {
    iStackRequestor->SearchL( aSearchString );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::ClientResponseRecivedLD
// Callback indicating that response was received within transaction.
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::ClientResponseRecivedLD(
    CUpnpHttpTransaction& aCompletedTrasaction )
    {
    TInt idx( iPendingTransactions.Find( &aCompletedTrasaction ) );
    //it should never happen that we received transaction that wasn't sent by us
    ASSERT( idx >= 0 );
    aCompletedTrasaction.ProcessResponseL();
    iPendingTransactions.Remove( idx );
    delete ( &aCompletedTrasaction );
    }

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::WlanLostOccurs
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::WlanLostOccurs()
    {
    iStackRequestor->StopHttpServer();
    TRAP_IGNORE( SetNullRequestorsL() );
    }
    
// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::AddressChanged
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::AddressChangedL()
    {
    iStackRequestor->StopHttpServer();
    iStackRequestor->StartHttpServerL();
    }    

// -----------------------------------------------------------------------------
// CUpnpCpbCurrentHttpClient::SetNullRequestorsL
//
// -----------------------------------------------------------------------------
//
void CUpnpCpbCurrentHttpClient::SetNullRequestorsL()
    {
    CUpnpCpHttpRequestorImplBase* httpReq = new ( ELeave ) CUpnpCpHttpRequestorImplBase();
    delete iHttpRequestorDefaultImpl;
    iHttpRequestorDefaultImpl = NULL;
    iHttpRequestorDefaultImpl = httpReq;
    iHttpRequestor = iHttpRequestorDefaultImpl;

    CUpnpCpStackRequestorImplBase* stackReq = new ( ELeave ) CUpnpCpStackRequestorImplBase();
    delete iStackRequestorDefaultImpl;
    iStackRequestorDefaultImpl = NULL;
    iStackRequestorDefaultImpl = stackReq;
    iStackRequestor = iStackRequestorDefaultImpl;
    }

//  End of File