bluetoothengine/btnotif/btnotifsrv/src/btnotifoutgoingpairinghandler.cpp
changeset 33 837dcc42fd6a
child 40 997690c3397a
child 42 b72428996822
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btnotif/btnotifsrv/src/btnotifoutgoingpairinghandler.cpp	Thu May 27 13:01:44 2010 +0300
@@ -0,0 +1,381 @@
+/*
+* Copyright (c) 2010 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: Pairing handler for local device initiated pairing
+*
+*/
+
+#include "btnotifoutgoingpairinghandler.h"
+#include <btengconstants.h>
+#include <btservices/btdevextension.h>
+#include "btnotifpairingmanager.h"
+
+/**  Length of the default PIN. */
+const TInt KDefaultHeadsetPinLength = 4;
+
+enum TPairingStageId
+    {
+    /**
+     * no pairing operation ongoing
+     */
+    ENoBonding = 0,
+    
+    /**
+     * pair with dedicated bonding method
+     */
+    EDedicatedBonding = 200,
+    
+    /**
+     * pair with general bonding by establishing L2CAP connection.
+     */
+    EGeneralBonding,  
+    
+    /**
+     * delaying next pairing request for a while
+     */
+    EGeneralBondingRetryTimer,
+    
+    /**
+     * The last pairing retry
+     */
+    EGeneralBondingRetry,
+    
+    /**
+     * disconnecting physical link after pairing operation.
+     * 
+     * todo: not used yet.
+     */
+    EDisconnectLinkAfterBonding,
+    };
+
+/**  SDP PSM (used for pairing) */
+const TInt KSDPPSM = 0x0001;
+
+// Delay time to void Repeated Attempts on pairing
+const TInt KGeneralBondingRetryDelayMicroSeconds = 5000000; // 5.0s
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifOutgoingPairingHandler::CBTNotifOutgoingPairingHandler( CBTNotifPairingManager& aParent, const TBTDevAddr& aAddr)
+    :  CBTNotifBasePairingHandler( aParent, aAddr )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd-phase constructor
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::ConstructL()
+    {
+    BaseConstructL();
+    User::LeaveIfError( iTimer.CreateLocal() );
+    }
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CBTNotifBasePairingHandler* CBTNotifOutgoingPairingHandler::NewL( CBTNotifPairingManager& aParent, 
+        const TBTDevAddr& aAddr )
+    {
+    CBTNotifOutgoingPairingHandler* self = new( ELeave ) CBTNotifOutgoingPairingHandler( aParent, aAddr );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifOutgoingPairingHandler::~CBTNotifOutgoingPairingHandler()
+    {
+    if ( iActive ) 
+        {
+        iActive->Cancel();
+        }
+    iBondingSession.Close();
+    iSocket.Close();
+    iTimer.Close();
+    }
+
+// ---------------------------------------------------------------------------
+// Simply deny the request as this is handing outgoing pairing
+// ---------------------------------------------------------------------------
+//
+TInt CBTNotifOutgoingPairingHandler::ObserveIncomingPair( const TBTDevAddr& /*aAddr*/ )
+    {
+    return KErrServerBusy;
+    }
+
+// ---------------------------------------------------------------------------
+// Accept the request only this device is not busy with another pairing request.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::HandleOutgoingPairL( const TBTDevAddr& aAddr, TUint aCod )
+    {
+    // TRACE_FUNC_ARG( ( _L(" cod 0x%08x"), aCod ) )
+    if ( iActive->IsActive() || aAddr != iAddr )
+        {
+        // we don't allow another pairing request.
+        User::Leave( KErrServerBusy );
+        }
+    
+    iAddr = aAddr;
+    iCod = TBTDeviceClass( aCod );
+    UnSetPairResult();
+    iParent.UnpairDevice( iAddr );
+    if ( CBtDevExtension::IsHeadset( iCod ) )
+        {
+        // If the devie is a headset, set to 0000 pin auto pairing
+        iPairMode = EBTOutgoingHeadsetAutoPairing;
+        }
+    else
+        {
+        iPairMode = EBTOutgoingNoneHeadsetPairing;
+        }
+    // SetOutgoPairProperty( iOutgoProperty, iAddr, iPairMode );
+    DoPairingL();
+    }
+
+// ---------------------------------------------------------------------------
+// Cancels an outstanding pair request by self-destruct
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::CancelOutgoingPair()
+    {
+    iParent.RenewPairingHandler( NULL );
+    }
+
+
+// ---------------------------------------------------------------------------
+// when phone initiated a pairing request towards a headset,
+// Pin code 0000 is first tried.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::GetPinCode( 
+        TBTPinCode& aPin, const TBTDevAddr& aAddr, TInt aMinPinLength )
+    {
+    aPin().iLength = 0;
+    if ( aMinPinLength <= KDefaultHeadsetPinLength 
+            && aAddr == iAddr
+            && iPairMode == EBTOutgoingHeadsetAutoPairing)
+        {
+        // if the pairing requires a stronger security level (indicated
+        // by aMinPinLength), 
+        // 0000 will not be supplied as it does not mmet the security
+        // requirements
+        const TUint8 KZeroPinValue = '0';
+        for (TInt i = 0; i < KDefaultHeadsetPinLength; ++i)
+            {
+            aPin().iPIN[i] = KZeroPinValue;
+            }
+        aPin().iLength = KDefaultHeadsetPinLength;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Abort pairing handling, request the owner to destroy this.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::StopPairHandling( const TBTDevAddr& aAddr )
+    {
+    if ( aAddr == iAddr )
+        {
+        iParent.OutgoingPairCompleted( KErrCancel );
+        iParent.RenewPairingHandler( NULL );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Pairing result will be received when pairing operation completes.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::DoHandlePairServerResult( TInt aResult )
+    {
+	if (aResult == (KHCIErrorBase-EPairingNotAllowed))
+		{
+		// if EPairingNotAllowed is recieved then any further pairing attempts will fail
+		// so don't attampt to pair
+        iPairMode = EBTOutgoingPairNone;
+		}
+    }
+
+// ---------------------------------------------------------------------------
+// Cancels possible outstanding pairing and notify user pair success.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::DoHandleRegistryNewPairedEvent( 
+        const TBTNamelessDevice& aDev )
+    {
+    TInt err( KErrNone );
+    // If pairing was performed using Just Works mode, we set a 
+    // UICookie to indicate that the device is successfully 
+    // bonded so that this device will be listed in paired device view of
+    // bluetooth application:
+    if ( aDev.LinkKeyType() == ELinkKeyUnauthenticatedNonUpgradable )
+        {
+        // TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair, Just Works pairing" ) ) );
+        err = iParent.AddUiCookieJustWorksPaired( aDev );
+        }
+    iActive->Cancel();
+    SetPairResult( err ? err : KErrNone );
+    iParent.OutgoingPairCompleted( err );
+    iParent.RenewPairingHandler( NULL );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBTNotifPairingAOObserver.
+// Based on the result code, decides the next operation, either try pairing 
+// with another mode, or complete pair request.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::RequestCompletedL( 
+        CBtSimpleActive* aActive, TInt aStatus )
+    {
+    // TRACE_FUNC_ARG( ( _L( "reqid %d, status: %d, pair mode %d " ), aId, aStatus, iPairMode ) )
+    if( aActive->RequestId() == EDedicatedBonding && 
+				( aStatus == KErrRemoteDeviceIndicatedNoBonding || 
+					( aStatus && iPairMode != EBTOutgoingNoneHeadsetPairing && iPairMode != EBTOutgoingPairNone ) )   )
+        {
+        // try general pairing if the remote doesn't have dedicated bonding, or
+        // pairing fails with a headset.
+        DoPairingL();
+        }
+    else if ( aStatus && iPairMode == EBTOutgoingHeadsetAutoPairing )
+        {
+        iPairMode = EBTOutgoingHeadsetManualPairing;
+        // auto pairing with headset failed, try to pair again with manual pin:
+        // ( void ) SetOutgoPairProperty( iOutgoProperty, iAddr, iPairMode );
+        // TRACE_INFO( _L( " auto pairing failed, switch to manual pairing") );     
+        DoPairingL();
+        }
+    else if ( aStatus && aActive->RequestId() == EGeneralBonding && 
+              iPairMode == EBTOutgoingHeadsetManualPairing )
+        {
+        // pairing headset with manual pin failed, wait for a while and try again:
+        iActive->SetRequestId( EGeneralBondingRetryTimer );
+        iTimer.After( iActive->iStatus, KGeneralBondingRetryDelayMicroSeconds );
+        iActive->GoActive();
+        }
+    else if( aActive->RequestId() == EGeneralBondingRetryTimer )
+        {
+        // try to pair headset again with manual pin again:
+        DoPairingL();
+        }
+    else if ( aStatus )
+        {
+        // we only starts showing note if pairing failed.
+        // For a successful pair, we must wait until registry has been updated.
+        if ( !IsPairResultSet() )
+            {
+            SetPairResult( aStatus );
+            }
+        if ( aStatus )
+            {
+            // todo: show error note?
+            iParent.OutgoingPairCompleted( aStatus );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBTEngActiveObserver.
+// cancels an outstanding request according to the given id.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::CancelRequest( TInt aRequestId )
+    {
+    switch ( aRequestId )
+        {
+        case EDedicatedBonding:
+            {
+            iBondingSession.Close();
+            }
+        case EGeneralBonding:
+        case EGeneralBondingRetry:
+            {
+            iSocket.CancelConnect();
+            iSocket.Close();
+            }
+        case EGeneralBondingRetryTimer:
+            {
+            iTimer.Cancel();
+            }     
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBTEngActiveObserver.
+// Handles a leave in RequestCompleted by self-destructing.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::HandleError( 
+        CBtSimpleActive* aActive, TInt aError )
+    {
+    // TRACE_FUNC_ARG( ( _L( "error: %d" ), aError ) )
+    // Our RunL can actually not leave, so we should never reach here.
+    (void) aActive;
+    iParent.OutgoingPairCompleted( aError );
+    iParent.RenewPairingHandler( NULL );
+    }
+
+// ---------------------------------------------------------------------------
+// decide the next state and issue pair request
+// ---------------------------------------------------------------------------
+//
+void CBTNotifOutgoingPairingHandler::DoPairingL()
+    {
+    // TRACE_FUNC_ENTRY
+    TPairingStageId currentMode = ( TPairingStageId ) iActive->RequestId();
+    ASSERT( !iActive->IsActive() );
+    TPairingStageId nextMode( EGeneralBonding );
+    
+    // if running BTv2.0 stack, dedicated bonding method 
+    // is not available.
+    if ( currentMode == ENoBonding && iParent.PairingServer() != NULL )
+        {
+        nextMode = EDedicatedBonding;
+        }
+    else if(currentMode == EGeneralBondingRetryTimer)
+        {
+        nextMode = EGeneralBondingRetry;
+        }
+    
+    // TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair::DoPairingL: bonding mode: pre %d, next %d"), currentMode, nextMode ) );
+    
+    iActive->SetRequestId( nextMode );
+    if ( nextMode == EDedicatedBonding )
+        {
+        iBondingSession.Start( *iParent.PairingServer(), iAddr, iActive->RequestStatus() );          
+        }
+    else
+        {
+        TBTServiceSecurity sec;
+        sec.SetAuthentication( ETrue );
+        iSockAddr.SetBTAddr( iAddr );
+        iSockAddr.SetPort(KSDPPSM);
+        iSockAddr.SetSecurity( sec );    
+        iSocket.Close();
+        User::LeaveIfError( iSocket.Open( iParent.SocketServ(), KL2CAPDesC ) );
+        iSocket.Connect( iSockAddr, iActive->RequestStatus() );
+        }
+    iActive->GoActive();
+    // TRACE_FUNC_EXIT
+    }
+