upnp/upnpstack/serviceframework/src/upnpdispatcherengine.cpp
changeset 0 f5a58ecadc66
child 9 5c72fd91570d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upnp/upnpstack/serviceframework/src/upnpdispatcherengine.cpp	Tue Feb 02 01:12:20 2010 +0200
@@ -0,0 +1,1151 @@
+/** @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 )
+        {
+        iCustomers.Append( &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.Append( (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.Append( 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.Append(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.Append(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.Append(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