bluetoothengine/btnotif/btnotifsrv/src/btnotifconnectiontracker.cpp
changeset 19 43824b19ee35
child 31 a0ea99b6fa53
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btnotif/btnotifsrv/src/btnotifconnectiontracker.cpp	Fri May 14 16:01:46 2010 +0300
@@ -0,0 +1,721 @@
+/*
+* ============================================================================
+*  Name        : btnotifconnectiontracker.cpp
+*  Part of     : bluetoothengine / btnotif
+*  Description : Bluetooth connection tracker and manager.
+*
+*  Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies).
+*  All rights reserved.
+*  This component and the accompanying materials are made available
+*  under the terms of "Eclipse Public License v1.0"
+*  which accompanies this distribution, and is available
+*  at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+*  Initial Contributors:
+*  Nokia Corporation - initial contribution.
+*
+*  Contributors:
+*  Nokia Corporation
+* ============================================================================
+* Template version: 4.1
+*/
+
+#include "btnotifconnectiontracker.h"
+#include <btextnotifiers.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <btextnotifierspartner.h>
+#endif
+
+#include "btnotifconnection.h"
+#include "btnotifsession.h"
+#include "btnotifclientserver.h"
+#include "bluetoothtrace.h"
+
+/**  Id for the link key watcher active object. */
+const TInt KLinkCountWatcher = 30;
+/**  Id for the pairing result watcher active object. */
+const TInt KSspResultWatcher = 31;
+/**  Id for the registry watcher active object (TEMP!). */
+const TInt KRegistryWatcher = 41;
+/**  Time window for determining if there are too many requests. */
+#ifndef __WINS__
+#define KDENYTHRESHOLD TTimeIntervalSeconds(3)
+#else   //__WINS__
+#define KDENYTHRESHOLD TTimeIntervalSeconds(5)
+#endif  //__WINS__
+
+
+// ======== LOCAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Checks if the notifier is one launched by the security manager of the
+// protocol stack. These notifiers need to be served unless really not possible.
+// ---------------------------------------------------------------------------
+//
+TBool IsStackSecmanNotifier( TInt aUid )
+    {
+    TBool result = EFalse;
+    if( aUid == KBTManAuthNotifierUid.iUid || aUid == KBTManPinNotifierUid.iUid ||
+        aUid == KBTPinCodeEntryNotifierUid.iUid || aUid == KBTNumericComparisonNotifierUid.iUid ||
+        aUid == KBTPasskeyDisplayNotifierUid.iUid )
+        {
+        result = ETrue;
+        }
+    return result;
+    }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnectionTracker::CBTNotifConnectionTracker( CBTNotifServer* aServer )
+:   iServer( aServer )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd-phase constructor
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::ConstructL()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    // Start watching the number of baseband links.
+    TInt err = iLinkCount.Attach( KPropertyUidBluetoothCategory,
+                KPropertyKeyBluetoothGetPHYCount );
+    // There is not much point to continue if we can't attach to
+    // the link count key.
+    User::LeaveIfError( err );
+    iLinkCountActive = CBtSimpleActive::NewL( *this, KLinkCountWatcher );
+    iLinkCount.Subscribe( iLinkCountActive->RequestStatus() );
+    iLinkCountActive->GoActive();
+    // Open a handle to the registry server
+    User::LeaveIfError( iBTRegistrySession.Connect() );
+    // Open a handle to the socket server
+    User::LeaveIfError( iSockServ.Connect() );
+    iPairingServ = new( ELeave ) RBluetoothPairingServer();
+    if( iPairingServ->Connect() )
+        {
+        // Delete in case of error - there is no good other way to keep track.
+        delete iPairingServ;
+        iPairingServ = NULL;
+        }
+    else
+        {
+        iSspResultActive = CBtSimpleActive::NewL( *this, KSspResultWatcher );
+        User::LeaveIfError( iSspResultSession.Open( *iPairingServ ) );
+        iSspResultSession.SimplePairingResult( iSspResultAddr, iSspResultActive->RequestStatus() );
+        iSspResultActive->GoActive();
+        }
+    iConnMan = CBTEngConnMan::NewL( this );
+    iPhyLinks = CBluetoothPhysicalLinks::NewL( *this, iSockServ );
+// ToDo: remove this when registry notifications API is available!!
+    err = iRegistryChange.Attach( KPropertyUidBluetoothCategory, KPropertyKeyBluetoothRegistryTableChange );
+    User::LeaveIfError( err );
+    iRegistryActive = CBtSimpleActive::NewL( *this, KRegistryWatcher );
+    iRegistryChange.Subscribe( iRegistryActive->RequestStatus() );
+    iRegistryActive->GoActive();
+// End ToDo
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// NewL.
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnectionTracker* CBTNotifConnectionTracker::NewL( CBTNotifServer* aServer )
+    {
+    CBTNotifConnectionTracker* self = new( ELeave ) CBTNotifConnectionTracker( aServer );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnectionTracker::~CBTNotifConnectionTracker()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    iConnArray.ResetAndDestroy();
+    iConnArray.Close();
+    iDeniedRequests.Close();
+    delete iLinkCountActive;
+    iLinkCount.Close();
+    
+    delete iConnMan;
+    delete iPhyLinks;
+    iSockServ.Close();
+    delete iSspResultActive;
+    iSspResultSession.Close();
+    if( iPairingServ )
+        {
+        iPairingServ->Close();
+        delete iPairingServ;
+        }
+    delete iRegistryActive;
+    iRegistryChange.Close();
+    iBTRegistrySession.Close();
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+// ---------------------------------------------------------------------------
+// Process a client message related to notifiers.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::DispatchNotifierMessageL( const RMessage2& aMessage )
+    {
+    BOstraceFunctionEntryExt ( DUMMY_LIST, this, aMessage.Function() );
+    TInt opcode = aMessage.Function();
+    TInt uid = aMessage.Int0();
+    const RMessage2* message = &aMessage;
+    // Use a pointer to the original message, so that we don't duplicate it.
+    // Then we avoid any bookkeeping for keeping them in sync.
+    if( opcode == EBTNotifCancelNotifier )
+        {
+        // We only accept a cancel message from the same session as the original
+        // request (this is enforced by the RNotifier backend). So we use the
+        // session of the cancel request (if this would change, the same way as
+        // for updates can be followed).
+        // We need to find the original request to identify the handler of the 
+        // connection; the uid points to the original request.
+        message = ( (CBTNotifSession *) aMessage.Session() )->FindMessageFromUid( uid );
+        }
+    else if( opcode == EBTNotifUpdateNotifier )
+        {
+        // We accept a update messages from any client, although in practice,
+        // they will all come from the same session (through RNotifier).
+        // We need to find the original request to identify the handler of the 
+        // connection (the uid points to the original request). Through the 
+        // server, we get it from any session.
+        message = iServer->FindMessageFromUid( uid );
+        }
+    if( !message )
+        {
+        // It's hard to continue if we don't know where to route the message.
+        User::Leave( KErrDisconnected );
+        }
+    TBuf8<0x250> paramsBuf;    // Size needs to be long enough to read all possible parameter sizes.
+    CBTNotifConnection* connection = FindConnectionFromMessageL( opcode, *message, paramsBuf );
+    if( !connection )
+        {
+        User::Leave( KErrDisconnected );
+        }
+    switch( opcode )
+        {
+        case EBTNotifStartSyncNotifier:
+        case EBTNotifStartAsyncNotifier:
+            connection->HandleNotifierRequestL( paramsBuf, aMessage );
+            break;
+        case EBTNotifUpdateNotifier:
+            connection->HandleNotifierUpdateL( paramsBuf, aMessage );
+            break;
+        case EBTNotifCancelNotifier:
+            // Complete the cancel message already here, so that the caller can
+            // continue, and the next operation can close sessions with the caller.
+            aMessage.Complete( KErrNone );
+            connection->CancelNotifierRequestL( *message );
+            break;
+        default:
+            break;
+        }
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handle a request related to pairing.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::HandleBondingRequestL( const RMessage2& aMessage )
+    {
+    BOstraceFunctionEntryExt ( DUMMY_LIST, this, aMessage.Function() );
+    // Bonding is an infrequently occurring operation, so we don't waste memory
+    // to keep a copy of the parameters. Instead we read them again when needed.
+    TPckgBuf<TBTDevAddr> addrBuf;
+    TInt opcode = aMessage.Function();
+    if( opcode == EBTEngPairDevice )
+        {
+        aMessage.ReadL( EBTNotifSrvParamSlot, addrBuf );
+        }
+    else if( opcode == EBTEngCancelPairDevice )
+        {
+        const RMessage2* message =
+                ( (CBTNotifSession *) aMessage.Session() )->FindMessageFromUid( EBTEngPairDevice );
+        message->ReadL( EBTNotifSrvParamSlot, addrBuf );
+        }
+    BtTraceBtAddr1( TRACE_DEBUG, DUMMY_LIST, "CBTNotifConnectionTracker::HandleBondingRequestL() addr=", addrBuf() );
+	TInt err = KErrNotFound;
+	CBTNotifConnection* connection = FindConnectionHandler( addrBuf() );
+    if( opcode == EBTEngPairDevice )
+        {
+        if( !connection )
+            {
+            // Create a connection first, then tell it to bond.
+            err = iPhyLinks->CreateConnection( addrBuf() );
+            connection = CBTNotifConnection::NewLC( addrBuf(), this );
+            iConnArray.AppendL( connection );
+            CleanupStack::Pop( connection );
+            }
+        else
+            {
+            // There is an existing connection. Care must be taken, the connection
+            // _should_ be disconnect first if this device is already paired, so that
+            // we are sure that we don't mix up the state of the connection.
+            RBTPhysicalLinkAdapter link;
+            err = link.Open( iSockServ, addrBuf() );
+            TUint32 linkState = 0;
+            if( !err )
+                {
+                err = link.PhysicalLinkState( linkState );
+                }
+            if( !err && linkState & ( ENotifyAuthenticationComplete | ENotifyEncryptionChangeOn ) )
+                {
+                // For now, we just reject the request.
+                err = KErrAlreadyExists;
+                }
+            link.Close();
+            }
+        if( !err )
+            {
+            // Start bonding immediately so that the connection object is in the right state.
+            connection->StartBondingL( aMessage );
+            }
+        }
+    else if( opcode == EBTEngCancelPairDevice && connection )
+        {
+        connection->CancelBondingL();
+        err = KErrNone;
+        aMessage.Complete( err );
+        }
+	// KErrNotFound is returned for a request to cancel pairing that has no connection.
+    if( err )
+        {
+        aMessage.Complete( err );
+        }
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handle a change in the number of connections.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::HandleLinkCountChangeL()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    TInt linkCount = 0;
+    User::LeaveIfError( iLinkCount.Get( linkCount ) );
+    if( linkCount )
+        {
+        RBTDevAddrArray links;
+        CleanupClosePushL( links );
+        User::LeaveIfError( iPhyLinks->Enumerate( links, 10 ) );
+        __ASSERT_ALWAYS( links.Count(), PanicServer( EBTNotifPanicBadState ) );
+        for( TInt i = iConnArray.Count() -1; i >= 0 ; i-- )
+            {
+            // Loop backwards, as we may remove entries from the array.
+
+            // First check the existing connections, and 
+            // remove disconnected links
+            TBTDevAddr addr = iConnArray[i]->Address();
+            TInt pos = links.Find( addr );
+            if( pos > KErrNotFound )
+                {
+                // The link we know is still connected,
+                // remove the watceher from the array.
+                links.Remove( pos );
+                // ToDo: see comment below!
+                }
+            else if( iConnArray[i]->CurrentOperation() == CBTNotifConnection::EIdle )
+                {
+                // This link is no more connected and idle, remove.
+                CBTNotifConnection* connection = iConnArray[i];
+                iConnArray.Remove( i ); // Does not delete the object.
+                delete connection;
+                }
+            // else we wait for the link to complete its operations.
+            }
+        // Now we have an array with only the new connections.
+        // Add new watchers.
+        for( TInt i = 0; i < links.Count(); i++ )
+            {
+            CBTNotifConnection* connection = CBTNotifConnection::NewLC( links[i], this );
+            iConnArray.AppendL( connection );
+            CleanupStack::Pop( connection );
+            }
+        // Close the links RBTDevAddrArray, needed before going out of scope.
+        CleanupStack::PopAndDestroy();
+        }
+    else
+        {
+        for( TInt i = iConnArray.Count() -1; i >= 0 ; i-- )
+            {
+            if( iConnArray[i]->CurrentOperation() == CBTNotifConnection::EIdle )
+                {
+                // This link is now idle, so we can remove it safely.
+                CBTNotifConnection* connection = iConnArray[i];
+                iConnArray.Remove( i ); // Does not delete the object.
+                delete connection;
+                }
+            }
+        if( !iConnArray.Count() )
+            {
+            // The array is idle, clean up the array resources.
+            iConnArray.Reset();
+            }
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Check if this device has been denied a connection already before.
+// Also check if a previous connection attempt has just been rejected.
+// ---------------------------------------------------------------------------
+//
+TBool CBTNotifConnectionTracker::UpdateBlockingHistoryL( const CBTDevice* aDevice, 
+    TBool aAccepted )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    __ASSERT_ALWAYS( aDevice, PanicServer( EBTNotifPanicBadArgument ) );
+    // Check the time since the previous event.
+    TBool result = RecordConnectionAttempts( aAccepted );
+    TInt pos = iDeniedRequests.Find( aDevice->BDAddr() );
+    if( !aAccepted )
+        {
+        if( pos == KErrNotFound )
+            {
+            // The user denied the request from a new device, record the device address.
+            if( aDevice->IsValidPaired() && aDevice->IsPaired() )
+                //[MCL]: && iDevice->LinkKeyType() != ELinkKeyUnauthenticatedUpgradable )
+                {
+                // Paired devices are allowed one time rejection without a prompt for blocking.
+                result = EFalse;
+                }
+            iDeniedRequests.AppendL( aDevice->BDAddr() );
+            }
+        // Nothing needed here if the address is already in the array.
+        }
+    else if( pos > KErrNotFound )
+        {
+        // The user accepted a request, and it was from a device he/she 
+        // previously rejected. Clear the history for this device from the array.
+        iDeniedRequests.Remove( pos );
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    return result;
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBluetoothPhysicalLinksNotifier.
+// Handle baseband connection completion.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::HandleCreateConnectionCompleteL( TInt aErr )
+    {
+    BOstraceFunctionEntryExt ( DUMMY_LIST, this, aErr );
+	// We only connect links for starting outgoing bonding.
+	const RMessage2* message = iServer->FindMessageFromUid( (TInt) EBTEngPairDevice );
+	if( message )
+		{
+        TPckgBuf<TBTDevAddr> addrBuf;
+        message->ReadL( EBTNotifSrvParamSlot, addrBuf );
+        CBTNotifConnection* connection = FindConnectionHandler( addrBuf() );
+        __ASSERT_ALWAYS( connection, PanicServer( EBTNotifPanicBadState ) );
+        if( !aErr && connection->CurrentOperation() == CBTNotifConnection::EIdle )
+            {
+			TRAP( aErr, connection->StartBondingL( *message ) );
+			}
+        if( aErr && connection->CurrentOperation() == CBTNotifConnection::EBonding )
+            {
+            connection->PairingResult( aErr );  // Launch error note
+            }
+		}
+	BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBluetoothPhysicalLinksNotifier.
+// Handle baseband disconnection.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::HandleDisconnectCompleteL( TInt aErr )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+	// We only disconnect links for starting outgoing bonding.
+	const RMessage2* message = iServer->FindMessageFromUid( (TInt) EBTEngPairDevice );
+	if( message )
+		{
+        TPckgBuf<TBTDevAddr> addrBuf;
+        message->ReadL( EBTNotifSrvParamSlot, addrBuf );
+		if( !aErr )
+			{
+			aErr = iPhyLinks->CreateConnection( addrBuf() );
+			}
+		if( aErr )
+			{
+			iServer->CompleteMessage( message->Handle(), aErr, KNullDesC8 );
+            CBTNotifConnection* connection = FindConnectionHandler( addrBuf() );
+            __ASSERT_ALWAYS( connection, PanicServer( EBTNotifPanicBadState ) );
+            connection->PairingResult( aErr );  // Launch error note
+			}
+    	}
+	BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBluetoothPhysicalLinksNotifier.
+// Handle disconnection of all links.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::HandleDisconnectAllCompleteL( TInt aErr )
+    {
+    (void) aErr;
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBTEngConnObserver.
+// Handle service-level connection completion.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::ConnectComplete( TBTDevAddr& aAddr, 
+    TInt aErr, RBTDevAddrArray* aConflicts )
+    {
+    (void) aAddr;
+    (void) aErr;
+    (void) aConflicts;
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBTEngConnObserver.
+// Handle service-level disconnection.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::DisconnectComplete( TBTDevAddr& aAddr, TInt aErr )
+    {
+    (void) aAddr;
+    (void) aErr;
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// Handle the active object completion.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::RequestCompletedL( CBtSimpleActive* aActive,
+    TInt aStatus )
+    {
+    BOstraceFunctionEntryExt ( DUMMY_LIST, this, aActive->RequestId() );
+    BOstraceExt2( TRACE_DEBUG, DUMMY_DEVLIST, 
+            "CBTNotifConnectionTracker::MBAORequestCompletedL() requestid=%d status=%d", 
+            aActive->RequestId(), aStatus);
+    if( aActive->RequestId() == KLinkCountWatcher )
+        {
+        iLinkCount.Subscribe( aActive->RequestStatus() );
+        aActive->GoActive();
+        if( !aStatus )
+            {
+            // HandleLinkCountChangeL();
+            }
+        }
+// ToDo: remove this when registry notifications API is available!!
+    else if( aActive->RequestId() == KRegistryWatcher )
+        {
+        // BTRegistry notifies of a change. Check which one.
+        iRegistryChange.Subscribe( aActive->RequestStatus() );
+        aActive->GoActive();
+        TInt tableChanged = 0;
+        if( !aStatus && !iRegistryChange.Get( tableChanged ) &&
+            tableChanged == KRegistryChangeRemoteTable )
+            {
+            // A record for a remote device has changed. Tell all 
+            // connections to update their record.
+            for( TInt i = 0; i < iConnArray.Count(); i++ )
+                {
+                // Reuse the functionality in the connection
+                if( iConnArray[i]->CurrentOperation() < CBTNotifConnection::EReadingRegistry )
+                    {
+                    iConnArray[i]->RequestCompletedL( aActive, aStatus );
+                    }
+                }
+            }
+        }
+// End ToDo
+    else if( aActive->RequestId() == KSspResultWatcher )
+        {
+        iSspResultSession.SimplePairingResult( iSspResultAddr, iSspResultActive->RequestStatus() );
+        iSspResultActive->GoActive();
+        CBTNotifConnection* connection = FindConnectionHandler( iSspResultAddr );
+        // ToDo: how to handle a result of a link that already disconnected? 
+        if( connection )
+            {
+            connection->PairingResult( aStatus );
+            }
+        }
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// Cancel and clean up all requests related to the active object.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::CancelRequest( TInt aRequestId )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    if( aRequestId == KLinkCountWatcher )
+        {
+        iLinkCount.Cancel();
+        }
+    else if( aRequestId == KSspResultWatcher )
+        {
+        iSspResultSession.CancelSimplePairingResult();
+        }
+    else if ( aRequestId == KRegistryWatcher )
+        {
+        iRegistryChange.Cancel();
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// 
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnectionTracker::HandleError( CBtSimpleActive* aActive, 
+        TInt aError )
+    {
+    (void) aActive;
+    (void) aError;
+    }
+
+// ---------------------------------------------------------------------------
+// Parse the details from a client message and find the associated handler.
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection* CBTNotifConnectionTracker::FindConnectionFromMessageL(
+    TInt aOpcode, const RMessage2& aMessage, TDes8& aBuffer )
+    {
+    BOstraceFunctionEntry1( DUMMY_DEVLIST, this );
+    TInt uid = aMessage.Int0();
+    aMessage.ReadL( EBTNotifSrvParamSlot, aBuffer );
+    TBTDevAddr addr = ParseAddressL( uid, aBuffer );
+    // If this is a 
+    CBTNotifConnection* connection = FindConnectionHandler( addr );
+    if( !connection && IsStackSecmanNotifier( uid ) &&
+        ( aOpcode == EBTNotifStartAsyncNotifier || aOpcode == EBTNotifStartSyncNotifier ) )
+        {
+        // A notifier from stack. This happens if e.g. the pairing
+        // request comes in before the link count changes (like security
+        // mode 3). Create the handler and queue the request.
+        // And note that 
+        connection = CBTNotifConnection::NewLC( addr, this );
+        iConnArray.AppendL( connection );
+        CleanupStack::Pop( connection );
+        }
+    BOstraceFunctionExitExt( DUMMY_DEVLIST, this, connection );
+    return connection;
+    }
+
+
+// ---------------------------------------------------------------------------
+// read the address from a client message.
+// ---------------------------------------------------------------------------
+//
+TBTDevAddr CBTNotifConnectionTracker::ParseAddressL( TInt aUid,
+    const TDesC8& aParamsBuf ) const
+    {
+    BOstraceFunctionEntry1( DUMMY_DEVLIST, this );
+    TBTDevAddr addr;
+    if( IsStackSecmanNotifier( aUid ) )
+        {
+        // For all these, the address is the first data member,
+        // so can be read using the TBTNotifierParams data structure.
+        TBTNotifierParams params;
+        TPckgC<TBTNotifierParams> paramsPckg( params );
+        paramsPckg.Set( aParamsBuf );
+        addr = paramsPckg().iBDAddr;
+        }
+    //else if(  ) other notifier types
+    BOstraceFunctionExitExt( DUMMY_DEVLIST, this, &addr );  
+    return addr;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Find a specific connection.
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection* CBTNotifConnectionTracker::FindConnectionHandler(
+    const TBTDevAddr& aAddr ) const
+    {
+    BOstraceFunctionEntry1( DUMMY_DEVLIST, this );
+    CBTNotifConnection* conn = NULL;
+    if( aAddr != TBTDevAddr() )
+        {
+        // This may be replaced by RArray::Find with appropriate key
+        for( TInt i = 0; i < iConnArray.Count(); i++ )
+            {
+            if( iConnArray[i]->Address() == aAddr )
+                {
+                conn = iConnArray[i];
+                break;
+                }
+            }
+        }
+    BOstraceFunctionExitExt( DUMMY_DEVLIST, this, conn );
+    return conn;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Record and check the time between connection attempts.
+// ---------------------------------------------------------------------------
+//
+TBool CBTNotifConnectionTracker::RecordConnectionAttempts( TBool aAccepted )
+    {
+    BOstraceFunctionEntry1( DUMMY_DEVLIST, this );
+    TBool result = ETrue;
+    TTime now( 0 );
+    if( !aAccepted )
+        {
+        now.UniversalTime();
+        if( iLastReject )
+            {
+            // Check the time between denied connections, that it does not go too fast.
+            TTimeIntervalSeconds prev( 0 );
+            if( !now.SecondsFrom( TTime( iLastReject ), prev ) )
+                {
+                if( prev <= KDENYTHRESHOLD )
+                    {
+                    // We are getting the requests too fast. Present the user with
+                    // an option to turn BT off.
+                    //iServer->SettingsTracker()->SetPower( EFalse );
+                    result = EFalse;
+                    }
+                }
+            }
+        }
+    // Record the current timestamp.
+    // It is reset in case the user accepted the request.
+    iLastReject = now.Int64();
+    BOstraceFunctionExitExt( DUMMY_DEVLIST, this, result );
+    return result;
+    }