upnp/upnpstack/serviceframework/src/upnpdispatcherengine.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:06:48 +0300
branchRCL_3
changeset 9 5c72fd91570d
parent 0 f5a58ecadc66
child 10 594d15129e2c
permissions -rw-r--r--
Revision: 201029 Kit: 201035

/** @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:  Message dispacher engine
*
*/


// INCLUDE FILES

#include "upnpdispatcherengine.h"
#include "upnphttpmessagefactory.h"
#include "upnphttpfileaccess.h"
#include "upnpdispatcherrequest.h"
#include "upnpdispatcherengineobserver.h"
#include "upnpcustomlog.h"
#include "upnphttpserversession.h"
#include "upnphttpserverruntime.h"
#include "upnpsettings.h"

#ifdef _DEBUG
#define KLogFile _L("UPnPStack.txt")
#endif

// CONSTANTS
const TInt KPortBufferLength = 10;
_LIT8(KMSearchConfig,"1,1,5,5,10");

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

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::CUpnpDispatcherEngine
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CUpnpDispatcherEngine::CUpnpDispatcherEngine(
                                      MDispatcherEngineObserver& aObserver )
    : CActive( EPriorityStandard ),
      iAddLocalPtr( NULL, 0 ),
      iObserver( aObserver ),
      iGetDevPtr( NULL, 0 ),
      iGetServPtr( NULL, 0 ),
      iRemoveUuidPtr( NULL, 0 ),
      iIsSessionOpen( EFalse )
    {
    CActiveScheduler::Add( this );
    iDeviceGetState = ENoOperation;
    iAddLocalBuffer = NULL;
    iRemoveUuid = NULL;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::ConstructL()
    {
#ifdef _DEBUG
    iReqsInStart = RThread().RequestCount();
    RThread().HandleCount( iProcessHandlesInStart, iThreadHandlesInStart );
#endif // _DEBUG

    User::LeaveIfError( iSession.Connect() );
    iIsSessionOpen = ETrue;
    iSession.RequestStartSsdpL();

    iActiveRequest = NULL;
    iSearch = NULL;

    ConstructHttpL();

    iDeviceGetState = ENoOperation;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::ConstructHttpL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::ConstructHttpL()
    {
    TInt iapId = CUpnpSettings::GetIapL();
    iHttpServerSession = CUpnpHttpServerSession::NewL( iapId, *this );    
    }
    
// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CUpnpDispatcherEngine* CUpnpDispatcherEngine::NewL(
        MDispatcherEngineObserver& aObserver )
    {
    CUpnpDispatcherEngine* self = NewLC( aObserver );
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CUpnpDispatcherEngine* CUpnpDispatcherEngine::NewLC(
        MDispatcherEngineObserver& aObserver )
    {
    CUpnpDispatcherEngine* self =
        new ( ELeave ) CUpnpDispatcherEngine( aObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::~CUpnpDispatcherEngine
// -----------------------------------------------------------------------------
//
CUpnpDispatcherEngine::~CUpnpDispatcherEngine()
    {
    // If active, calls DoCancel
    Cancel();

    delete iRemoveUuid;
    iRemoveUuid = NULL;

    delete iAddLocalBuffer;
    iAddLocalBuffer = NULL;

    delete iSearch;
    iSearch = NULL;

    delete iUuids;
    iUuids = NULL;

    delete [] iDevs;
    delete [] iServs;
    
    iSession.Close();
    iIsSessionOpen = EFalse;
    iCustomers.Reset();

    if ( iHttpServerSession )
        {
        iHttpServerSession->Stop();
        delete iHttpServerSession;
        }

    iPendingRequests.ResetAndDestroy();

    iNewDevices.ResetAndDestroy();

    RemoveHandledRequest();

    delete iMXString;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::AddCustomer
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::AddCustomer( const MUpnpDispatcherCustomer& aCustomer )
    {
    // adds a new customer for CUpnpDispatcherEngine
    if ( iCustomers.Find( &aCustomer ) == KErrNotFound )
        {
        TRAP_IGNORE(iCustomers.AppendL( &aCustomer ));
        }
    }
// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::RemoveCustomer
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::RemoveCustomer( const MUpnpDispatcherCustomer& aCustomer )
    {
    TInt pos = iCustomers.Find( &aCustomer );
    if ( pos != KErrNotFound )
        {
        LOGS2("CUpnpDispatcherEngine::RemoveCustomer, removing customer 0x%x from position %d", &aCustomer, pos);
        iCustomers.Remove( pos );
        iCustomers.Compress();
        LOGS("CUpnpDispatcherEngine::RemoveCustomer done");
        }
    else
        LOGS1("CUpnpDispatcherEngine::RemoveCustomer, customer 0x%x not found", &aCustomer);
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::SendMessageL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::SendMessageL( CUpnpHttpMessage* aMessage )
    {
    // Sends a Http message
    iHttpServerSession->SendMessageL( aMessage );
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::UpdateDevicesL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::UpdateDevicesL( TInt aUpdateId )
    {
    // checking if new list size is called.
    if ( iDeviceGetState != EGetListSize )
        {
        if ( IsActive() )
            {
            return;
            }

        // setting information for message handler
        // iSize contains information about last known
        // update id. On return, it will contain also
        // number of new devices and servises.

        if( iSize.iUpdateId > iOldUpdateId )
            {
            iDeviceGetState = EGetList;
            SetActive();
            iStatus = KRequestPending;
            TRequestStatus* stat = &iStatus;
            User::RequestComplete( stat, KErrNone );
            }
        else
            {
            iSize.iUpdateId = aUpdateId;
            iOldUpdateId = aUpdateId;

            iStatus = KRequestPending;
            // connection restoring
            if(!iIsSessionOpen)
                {
                User::LeaveIfError( iSession.Connect() );
                iIsSessionOpen = ETrue;
                }

            iSession.RequestGetDeviceListSize( iStatus, iSize );
            if( !IsActive() )
                {
                SetActive();
                }
                iDeviceGetState = EGetList;
            }
        }
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::GetDevicesL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CUpnpDispatcherEngine::TDispatcherRequest CUpnpDispatcherEngine::GetDevicesL()
    {
    LOG_FUNC_NAME;

    TDispatcherRequest status( ENewDevices );
    if ( iDevs )
        {
        delete [] iDevs;
        iDevs = NULL;
        }

    if ( iServs )
        {
        delete [] iServs;
        iServs = NULL;
        }

    // checking if new devices or services has been found.
    if ( iSize.iUpdateId > iOldUpdateId )
        {
        if( IsActive() )
            {
            Cancel();
            }

        // constructing buffers for getting the information
        // for new devices and services.
        // iDevs is an array, that will have number of
        // devices as we have just received from Message Handler
        // Same with iServs for services.

        iDevs = new (ELeave) TUpnpDevice[iSize.iDeviceCount];
        iServs = new (ELeave) TUpnpService[iSize.iServiceCount];

        TPtr8 devPtr( reinterpret_cast<TUint8*>( iDevs ),
            iSize.iDeviceCount*sizeof( TUpnpDevice ),
            iSize.iDeviceCount*sizeof( TUpnpDevice ) );
        TPtr8 servPtr( reinterpret_cast<TUint8*>( iServs ),
            iSize.iServiceCount*sizeof( TUpnpService ),
            iSize.iServiceCount*sizeof( TUpnpService ) );

        // setting member pointers to point to strictures that will be
        // filled with device and service information as call returns.
        iGetDevPtr.Set(devPtr);
        iGetServPtr.Set(servPtr);

        // connection restoring
        if(!iIsSessionOpen)
            {
            User::LeaveIfError( iSession.Connect() );
            iIsSessionOpen = ETrue;
            }

        iStatus = KRequestPending;
        iSession.RequestGetDeviceList( iStatus, iGetDevPtr, iGetServPtr );
        if( !IsActive() )
            {
            SetActive();
            }

        status = ENewDevices;
        }
    else
        {
        // if no new devices, return the request for Message Handler,
        // so it can complete message when there will be new devices.
        UpdateDevicesL(iSize.iUpdateId);

        status = EDeviceList;
        }

    return status;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::DevicesReceivedL
// -----------------------------------------------------------------------------
//
TInt CUpnpDispatcherEngine::DevicesReceivedL()
    {
    if( iDevs && iServs)
        {
        TInt servIndex = 0;

        // parsing data to devices and services.
        for ( TInt i = 0; i < iSize.iDeviceCount; i++ )
            {
            RPointerArray<TUpnpService> currServs;
            CleanupClosePushL( currServs );
            for ( TInt j = 0; j < iDevs[i].iServiceCount; j++ )
                {
                currServs.AppendL( (const TUpnpService*)&iServs[servIndex+j] );
                }
            CleanupStack::Check(&currServs);
            servIndex += iDevs[i].iServiceCount;

            // creating CUpnpDevice objects from this information.

            CUpnpDevice* device = CUpnpDevice::NewL( &iDevs[i], currServs );
            CleanupStack::Check(&currServs);
            device->SetAlive( iDevs[i].iAlive );
            CleanupStack::Check(&currServs);
            currServs.Reset();
            CleanupStack::Pop( &currServs );

            iNewDevices.AppendL( device );
            }

        delete[] iDevs;
        iDevs = NULL;

        delete[] iServs;
        iServs = NULL;

        iOldUpdateId = iSize.iUpdateId;

        // inform CUpnpDispatcher that new devices and services has been found.
        iObserver.DeviceListReceivedL(iOldUpdateId);
        }
    //The UpdateId should be passed back to the DispatcherEngine
    //(Through Observer)
    return iOldUpdateId;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::NewDevices
// -----------------------------------------------------------------------------
//
const RPointerArray<CUpnpDevice>& CUpnpDispatcherEngine::NewDevices() const
    {
    return iNewDevices;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::RemoveDevices
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::RemoveDevices()
    {
    iNewDevices.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::AddLocalDeviceL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::AddLocalDeviceL( const TDesC8& aUuid,
                                             const TDesC8& aDeviceType,
                                             const TDesC8& aDescriptionPath,
                                             const CDesC8Array& aServices,
                                             const TBool aIsRootDevice )
    {
    // checking if client is busy.
    if ( iDeviceGetState != EOtherOperation &&
        iDeviceGetState != EListReceived)
        {
        if ( IsActive() )
            {
            Cancel();
            }

        TBuf8<KPortBufferLength> port;
        port.Num( HttpServerAddress().Port() );

        _LIT8( KRootDevice, "r" );

        TInt bufLen = aUuid.Length() +
            aDeviceType.Length() +
            aDescriptionPath.Length() +
            port.Length() + KRootDevice().Length();

        TInt i=0;
        for ( i = 0; i < aServices.Count(); i++ )
            {
            bufLen += aServices[i].Length();
            }

        if(iAddLocalBuffer)
            {
            delete iAddLocalBuffer;
            iAddLocalBuffer = NULL;
            }

        // creating a buffer that will hold information about device
        // that is to be added.

        iAddLocalBuffer = HBufC8::NewL( bufLen );
        iAddLocalPtr.Set( iAddLocalBuffer->Des() );

        // iAddLocalDevice is a struct, that will hold length of each
        // data in the buffer. When we have length of each data and
        // the data buffer, we can parse the data back to separate
        // buffers on server side.

        iAddLocalDevice.iUuidLength = aUuid.Length();
        iAddLocalDevice.iDeviceTypeLength = aDeviceType.Length();
        iAddLocalDevice.iDescriptionUrlLength = aDescriptionPath.Length();
        iAddLocalDevice.iDomainLength = 0;
        iAddLocalDevice.iPortNumberLength = port.Length();
        iAddLocalDevice.iRootDeviceLength = 0;

        iAddLocalPtr.Append( aUuid );
        iAddLocalPtr.Append( aDeviceType );
        iAddLocalPtr.Append( aDescriptionPath );
        iAddLocalPtr.Append( port );

                if ( aIsRootDevice )
                    {
                    iAddLocalPtr.Append( KRootDevice() );
                    iAddLocalDevice.iRootDeviceLength = KRootDevice().Length();
                    }

        for ( i = 0; i < aServices.Count(); i++ )
            {
            iAddLocalDevice.iServiceLength[i] = aServices[i].Length();
            iAddLocalPtr.Append( aServices[i] );
            }

        for ( ; i < KMaxServiceCount; i++ )
            {
            iAddLocalDevice.iServiceLength[i] = 0;
            }

        iAddLocalDevice.iBufferLength = iAddLocalPtr.Length();

        // connection restoring
        if(!iIsSessionOpen)
            {
            User::LeaveIfError( iSession.Connect() );
            iIsSessionOpen = ETrue;
            }

        iStatus = KRequestPending;
        iSession.RequestAddLocalDevice( iStatus, iAddLocalDevice,
            iAddLocalPtr );
        if( !IsActive() )
            {
            SetActive();
            }

        iDeviceGetState = EOtherOperation;
        }
    else
        {
        // if client is busy, making a request to request queue.
        CUpnpDispatcherRequest* request = CUpnpDispatcherRequest::NewLC(
            EAddLocalDevice );

        request->AddArgumentL( aUuid );
        request->AddArgumentL( aDeviceType );
        request->AddArgumentL( aDescriptionPath );

        _LIT8( KRootDevice, "r" );

        if ( aIsRootDevice )
            {
            request->AddArgumentL( KRootDevice );
            }
        else
            {
            request->AddArgumentL( KNullDesC8 );
            }

        TInt granularity = aServices.Count();
        if( 0 == granularity )
            {
            granularity = 1;
            }
        CDesC8ArrayFlat* array = new (ELeave) CDesC8ArrayFlat( granularity );

        CleanupStack::PushL(array);

        for ( TInt k = 0; k < aServices.Count(); k++ )
            {
            array->AppendL( aServices[k] );
            }

        CleanupStack::Pop(array);
        request->AddServices(array);

        CleanupStack::Pop(request);
        iPendingRequests.AppendL(request);
        }
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::AddControlPointClientL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::AddControlPointClientL()
    {
    // checking if client is busy.
    if ( iDeviceGetState != EOtherOperation &&
        iDeviceGetState != EListReceived )
        {
        if ( IsActive() )
            {
            Cancel();
            }

        // connection restoring
        if ( !iIsSessionOpen )
            {
            User::LeaveIfError( iSession.Connect() );
            iIsSessionOpen = ETrue;
            }

        iStatus = KRequestPending;
        iSession.RequestAddControlPoint( iStatus );

        if ( !IsActive() )
            {
            SetActive();
            }
        iDeviceGetState = EOtherOperation;
        }
    else
        {
        // client is busy, making a request and adding it to queue.
        CUpnpDispatcherRequest* request =
            CUpnpDispatcherRequest::NewLC( EAddControlPointClient );
        iPendingRequests.AppendL( request );
        CleanupStack::Pop( request );
        }
    }

void CUpnpDispatcherEngine::RemoveControlPointClientL()
    {
    // checking if client is busy.
    if ( iDeviceGetState != EOtherOperation &&
        iDeviceGetState != EListReceived )
        {
        if ( IsActive() )
            {
            Cancel();
            }

        // connection restoring
        if ( !iIsSessionOpen )
            {
            User::LeaveIfError( iSession.Connect() );
            iIsSessionOpen = ETrue;
            }

        iStatus = KRequestPending;
        iSession.RequestRemoveControlPoint( iStatus );

        if ( !IsActive() )
            {
            SetActive();
            }
        iDeviceGetState = EOtherOperation;
        }
    else
        {
        // client is busy, making a request and adding it to queue.
        CUpnpDispatcherRequest* request =
                CUpnpDispatcherRequest::NewLC( ERemoveControlPointClient );
        iPendingRequests.AppendL( request );
        CleanupStack::Pop( request );
        }
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::SsdpSearchL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::SsdpSearchL( const TDesC8& aString )
    {
    if(!iMXString)
        {
        TRAPD(err,iMXString = CUpnpSettings::GetMSearchConfigurationL());
        if(err == KErrNotFound)
            {
            iMXString = KMSearchConfig().AllocL();
            }
        else
            {
            User::LeaveIfError(err);
            }
        }

    if( aString.Length() <= 0 )
        {
        return;
        }

    // checking if client is busy.
    if ( iDeviceGetState != EOtherOperation &&
        iDeviceGetState != EListReceived )
        {
        if ( IsActive() )
            {
            Cancel();
            }

        if( iSearch )
            {
            delete iSearch;
            iSearch = NULL;
            }

        iSearch = HBufC8::NewL( aString.Length() );
        iSearch->Des().Zero();
        iSearch->Des().Append( aString );
        // connection restoring
        if(!iIsSessionOpen)
            {
            User::LeaveIfError( iSession.Connect() );
            iIsSessionOpen = ETrue;
            }

        iStatus = KRequestPending;
        iSession.RequestSsdpSearch( iStatus, *iSearch, *iMXString );

        if( !IsActive() )
            {
            SetActive();
            }

        iDeviceGetState = EOtherOperation;
        }
    else
        {
        // client is busy, making a request and adding it to queue.
        CUpnpDispatcherRequest* request = CUpnpDispatcherRequest::NewLC( ESsdpSearch );

        request->AddArgumentL( aString );

        CleanupStack::Pop(request);
        iPendingRequests.AppendL(request);
        }
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::SsdpStopFilteringL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::SsdpStopFilteringL( const TDesC8& aString )
    {
    if( aString.Length() <= 0 )
        {
        return;
        }
    if( iUuids )
        {
        delete iUuids;
        iUuids = NULL;
        }
    iUuids = HBufC8::NewL( aString.Length() );
    iUuids->Des().Zero();
    iUuids->Des().Append( aString );
    // connection restoring
    if(!iIsSessionOpen)
        {
        User::LeaveIfError( iSession.Connect() );
        iIsSessionOpen = ETrue;
        }
    iSession.RequestStopFiltering( *iUuids );
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::HttpEventLD
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::HttpEventLD( CUpnpHttpMessage* aMessage )
    {
    if( !aMessage )
        {
        return;
        }
    CleanupStack::PushL( aMessage );

    HBufC8* customerPath = aMessage->ServicePath().AllocLC();
    for ( TInt i = 0; i < iCustomers.Count(); i++ )
        {
        MUpnpDispatcherCustomer* customer = iCustomers[i];
        if ( customerPath->CompareF( customer->Path() ) == 0 )
            {
            CleanupStack::PopAndDestroy(customerPath);
            CleanupStack::Pop( aMessage );
            customer->MessageReceivedLD( aMessage );
            return;
            }
        }
    CleanupStack::PopAndDestroy(customerPath);
    
    if ( aMessage->Type() <= ETransferStart )
        {
        CUpnpHttpMessage* reply = RUpnpHttpMessageFactory::HttpResponseErrorL(
                                                        aMessage->Sender(), EHttpBadRequest );
        CleanupStack::PushL( reply );
        reply->SetSessionId( aMessage->SessionId() );
        SendMessageL( reply );
        CleanupStack::PopAndDestroy( reply );
        }
    CleanupStack::PopAndDestroy( aMessage );
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::HttpServerAddressL
// -----------------------------------------------------------------------------
//
TInetAddr CUpnpDispatcherEngine::HttpServerAddress()
    {
    TInetAddr addr;
    iHttpServerSession->GetAddress( addr );
    return addr;
    }

// CUpnpDispatcherEngine::RemoveLocalDeviceL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::RemoveLocalDeviceL( const TDesC8& aUuid, TBool aSilent )
    {
    // checking if client is busy.
    if ( iDeviceGetState != EOtherOperation &&
         iDeviceGetState != EListReceived )
        {
        if ( IsActive() )
            {
            Cancel();
            }

        if(iRemoveUuid)
            {
            delete iRemoveUuid;
            iRemoveUuid = NULL;
            }

        iRemoveUuid = aUuid.AllocL();
        iRemoveUuidPtr.Set(iRemoveUuid->Des());

        // connection restoring
        if(!iIsSessionOpen)
            {
            User::LeaveIfError( iSession.Connect() );
            iIsSessionOpen = ETrue;
            }

        iStatus = KRequestPending;

        if (!aSilent)
            {
            iSession.RequestRemoveLocalDevice( iStatus, iRemoveUuidPtr );
            }
        else
            {
            iSession.RequestRemoveSilentLocalDevice( iStatus, iRemoveUuidPtr );
            }
        iDeviceGetState = EOtherOperation;

        if( !IsActive() )
            {
            SetActive();
            }
        }
    else
        {
        // client is busy, making a request and adding it to queue.
        CUpnpDispatcherRequest* request = CUpnpDispatcherRequest::NewLC(
            ERemoveLocalDevice );

        request->AddArgumentL( aUuid );

        // we need to store information if the removal should be silent
        if ( aSilent )
            {
            request->AddArgumentL( KNullDesC8 );
            }

        CleanupStack::Pop(request);
        iPendingRequests.AppendL(request);
        }
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::MacAddressL
// -----------------------------------------------------------------------------
//
const HBufC8* CUpnpDispatcherEngine::MacAddressL()
    {
    TSockAddr* addr;
    addr = iHttpServerSession->HWAddressL();
    CleanupStack::PushL( addr);
    TInt i = 0;
    HBufC8* hwAddr = NULL;
    hwAddr = HBufC8::NewL( 2 * addr->GetUserLen() );
    hwAddr->Des().Zero();

    for ( i = sizeof(SSockAddr); i < sizeof(SSockAddr) + addr->GetUserLen(); i++ )
        {
        hwAddr->Des().AppendNumFixedWidth((*addr)[i], EHex, 2);
        }

    CleanupStack::PopAndDestroy( addr);

    hwAddr->Des().UpperCase();

    return hwAddr;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::RunL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::RunL()
    {
    if ( iStatus.Int() == KErrServerTerminated || iStatus.Int() == KErrCancel )
        {
        LOGS("CUpnpDispatcherEngine::RunL, Server terminated or canceled, trying to restart");
        iSession.Close();
        iIsSessionOpen = EFalse;
        return;
        }

    switch( iDeviceGetState )
        {
        case EOtherOperation:
            if ( iPendingRequests.Count() > 0 )
                {
                HandlePendingRequestL();
                }
            else
                {
                UpdateDevicesL(iOldUpdateId);
                }
            break;
        case EGetListSize:
            UpdateDevicesL(iOldUpdateId);
            break;
        case EGetList:
            if( GetDevicesL() == EDeviceList)
                {
                iDeviceGetState = EGetList;
                }
            else
                {
                iDeviceGetState = EListReceived;
                }

            break;
        case EListReceived:
            if( iSize.iUpdateId >= iOldUpdateId )
                {
                DevicesReceivedL();
                }
            if( iPendingRequests.Count() > 0 && !IsActive())
                {
                iDeviceGetState = EOtherOperation;
                //Re-execute RunL to launch HandlePendingRequest
                SetActive();
                iStatus = KRequestPending;
                TRequestStatus* stat = &iStatus;
                User::RequestComplete( stat, KErrNone );
                break;
                }
            UpdateDevicesL(iOldUpdateId);

            break;
        default: //NoOperation
            break;
        }
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::RunError
// RunError in case RunL leaves.
// -----------------------------------------------------------------------------
//
TInt CUpnpDispatcherEngine::RunError( TInt /*aError*/ )
    {
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::DoCancel
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::DoCancel()
    {
    TRAP_IGNORE( StopRequestL() );

    if(iDevs)
        {
        delete [] iDevs;
        iDevs = NULL;
        }
    if(iServs)
        {
        delete [] iServs;
        iServs = NULL;
        }

    iDeviceGetState = ENoOperation;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::HandlePendingRequestL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::HandlePendingRequestL()
    {
    ASSERT( iPendingRequests.Count() > 0 );
    RemoveHandledRequest();
    iActiveRequest = iPendingRequests[0];
    CDesC8ArrayFlat& arguments = iActiveRequest->Arguments();
    switch( iActiveRequest->Request() )
        {
        case EAddLocalDevice:
            {
            if( iDeviceGetState == EOtherOperation )
                {
                iDeviceGetState = ENoOperation;
                }

            if ( arguments[3].Length() > 0 )
                {
                AddLocalDeviceL(
                                arguments[0],
                                arguments[1],
                                arguments[2],
                                iActiveRequest->Services(),
                        ETrue );
                }
            else
                {
                AddLocalDeviceL(
                                arguments[0],
                                arguments[1],
                                arguments[2],
                                iActiveRequest->Services(),
                                EFalse );
                }

            }
            break;

        case ERemoveLocalDevice:
            {

            if( iDeviceGetState == EOtherOperation )
                {
                iDeviceGetState = ENoOperation;
                }

            // the presence of 2nd argument means the removal should be silent
            TBool silent = EFalse;
            if ( arguments.Count() == 2 )
                {
                silent = ETrue;
                }
            RemoveLocalDeviceL( arguments[0], silent );
            }
            break;

        case EAddControlPointClient:
            {
            if( iDeviceGetState == EOtherOperation )
                {
                iDeviceGetState = ENoOperation;
                }
                AddControlPointClientL();
            }
            break;

        case ERemoveControlPointClient:
            {
            if( iDeviceGetState == EOtherOperation )
                {
                iDeviceGetState = ENoOperation;
                }

            RemoveControlPointClientL();
            }
            break;

        case ESsdpSearch:
            {

            if( iDeviceGetState == EOtherOperation )
                {
                iDeviceGetState = ENoOperation;
                }

            SsdpSearchL( arguments[0] );

            }
        default:
            break;
        }
    iPendingRequests.Remove( 0 );
    iPendingRequests.Compress();
    iDeviceGetState = EOtherOperation;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::RemoveHandledRequest
// -----------------------------------------------------------------------------
//
TInt CUpnpDispatcherEngine::RemoveHandledRequest()
    {
    if(iActiveRequest)
        {
        // If last message was ssdp search, now it is safe
        // to delete iSearch also.
        if( iActiveRequest->Request() == ESsdpSearch )
            {
            if( iSearch )
                {
                delete iSearch;
                iSearch = NULL;
                }
            }
        delete iActiveRequest;
        iActiveRequest = NULL;
        return KErrNone;
        }
    return KErrNotFound;
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::StopRequestL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::StopRequestL()
    {
    //LOGSH( iHandle, "Disp Request Cancelled");

    if( iDeviceGetState == EGetList )
        {
        // connection restoring
        if(!iIsSessionOpen)
            {
            User::LeaveIfError( iSession.Connect() );
            iIsSessionOpen = ETrue;
            }

        iDeviceGetState = ENoOperation;
        iSession.RequestStop();
        }
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcherEngine::SetTransactionCreator
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::SetTransactionCreator( 
          MUpnpHttpServerTransactionCreator* aTransactionCreator )
    {
    iHttpServerSession->DefaultRuntime().SetCreator( *aTransactionCreator );
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcher::StartHttpServerL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::StartHttpServerL( TBool aRegister , const TInt aPort )
    {
    iHttpServerSession->StartL( aPort );    
    CheckErrorL( aRegister );
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcher::CheckErrorL
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::CheckErrorL( TBool /*aRegister*/ )
    {
    TInt error = KErrNone;
    iSession.RequestCheckError(error);
    User::LeaveIfError(error);
    }

// -----------------------------------------------------------------------------
// CUpnpDispatcher::StopHttpServer
// -----------------------------------------------------------------------------
//
void CUpnpDispatcherEngine::StopHttpServer()
    {
    iHttpServerSession->Stop();
    }

//  End of File