/*
* Copyright (c) 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: Implementation of BTEng server session handling
*
*/
#include <e32base.h>
#include "btengsrvsession.h"
#include "btengserver.h"
#include "btengsrvbbconnectionmgr.h"
#include "btengpairman.h"
#include "btengclientserver.h"
#include "debug.h"
/** The message argument which holds the client event package. */
const TInt KBTEngEventSlot = 2;
// ======== MEMBER FUNCTIONS ========
// ---------------------------------------------------------------------------
// C++ default constructor
// ---------------------------------------------------------------------------
//
CBTEngSrvSession::CBTEngSrvSession()
: CSession2()
{
}
// ---------------------------------------------------------------------------
// Symbian 2nd-phase constructor
// ---------------------------------------------------------------------------
//
void CBTEngSrvSession::ConstructL()
{
TRACE_FUNC_ENTRY
//create queue for storing multiple connection events
iConnectionEventQueue = new (ELeave) CDesC8ArraySeg(1);
}
// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
CBTEngSrvSession* CBTEngSrvSession::NewL()
{
CBTEngSrvSession* self = new( ELeave ) CBTEngSrvSession();
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CBTEngSrvSession::~CBTEngSrvSession()
{
TRACE_FUNC_ENTRY
if( !iNotifyConnMessage.IsNull() )
{
iNotifyConnMessage.Complete( KErrCancel );
}
CancelPairRequest();
if( Server() )
{
Server()->RemoveSession( iAutoSwitchOff );
}
delete iConnectionEventQueue;
TRACE_FUNC_EXIT
}
// ---------------------------------------------------------------------------
// Complete the construction of the session.
// ---------------------------------------------------------------------------
//
void CBTEngSrvSession::CreateL()
{
TRACE_FUNC_ENTRY
Server()->AddSession();
}
// ---------------------------------------------------------------------------
// Notify the client of the connection event.
// ---------------------------------------------------------------------------
//
void CBTEngSrvSession::NotifyConnectionEvent(const TBTDevAddr aAddr,
TBTEngConnectionStatus aConnStatus, RBTDevAddrArray* aArray, TInt aErr)
{
TRACE_FUNC_ENTRY
TRACE_INFO((_L("[BTEng]\t Informing client %d"), iNotifyConnMessage.Handle()));
//package up connection event to send to the client
TBTEngEventPkg pkg;
pkg().iAddr = aAddr;
pkg().iConnEvent = aConnStatus;
pkg().iConflictsBuf.Zero();
if (aArray)
{
TBTDevAddrPckgBuf addr;
for (TInt i = 0; i < aArray->Count(); i++)
{
addr = (*aArray)[i];
pkg().iConflictsBuf.Append(addr);
}
}
TInt err = KErrNotFound;
//if a client message is outstanding
if (!iNotifyConnMessage.IsNull())
{
//complete the message prioritising the main error
err = iNotifyConnMessage.Write(KBTEngEventSlot, pkg);
aErr = (aErr != KErrNone) ? aErr : err;
iNotifyConnMessage.Complete(aErr);
}
//if there is no client message outstanding or the write failed
if (err != KErrNone)
{
//if the append fails we can't do anything with the error so ignore
//it and let the event get dropped
TRAP_IGNORE(iConnectionEventQueue->AppendL(pkg));
}
}
// ---------------------------------------------------------------------------
// Comfirm the caller if pairing request is completed in this invoke.
// ---------------------------------------------------------------------------
//
TInt CBTEngSrvSession::CompletePairRequest( TInt aResult )
{
if ( !iPairMessage.IsNull())
{
iPairMessage.Complete( aResult );
return KErrNone;
}
return KErrNotFound;
}
// ---------------------------------------------------------------------------
// From class CSession2
// Handles servicing of a client request that has been passed to the server.
// ---------------------------------------------------------------------------
//
void CBTEngSrvSession::ServiceL( const RMessage2& aMessage )
{
TRAPD( err, DispatchMessageL( aMessage ) );
if( !aMessage.IsNull() &&
( err ||
( aMessage.Function() != EBTEngNotifyConnectionEvents &&
aMessage.Function() != EBTEngPairDevice ) ) )
{
// Return the error code to the client.
aMessage.Complete( err );
}
}
// ---------------------------------------------------------------------------
// Returns a handle to CBTEngServer.
// ---------------------------------------------------------------------------
//
CBTEngServer* CBTEngSrvSession::Server()
{
return (CBTEngServer*) CSession2::Server();
}
// ---------------------------------------------------------------------------
// Handles a client request that has been passed to the server.
// ---------------------------------------------------------------------------
//
void CBTEngSrvSession::DispatchMessageL( const RMessage2& aMessage )
{
TRACE_FUNC_ENTRY
TInt opcode = aMessage.Function();
switch( opcode )
{
case EBTEngSetPowerState:
{
iAutoSwitchOff = (TBool) aMessage.Int1();
Server()->SetPowerStateL( (TBTPowerStateValue) aMessage.Int0(),
iAutoSwitchOff );
}
break;
case EBTEngSetVisibilityMode:
{
Server()->SetVisibilityModeL( (TBTVisibilityMode) aMessage.Int0(),
aMessage.Int1() );
}
break;
case EBTEngNotifyConnectionEvents:
{
//ensure the message contains the correctly sized descriptor
if (aMessage.GetDesMaxLengthL(KBTEngEventSlot) != sizeof(TBTEngEventMsg))
{
User::Leave(KErrBadDescriptor);
}
if(!iNotifyConnMessage.IsNull())
{
User::Leave(KErrInUse);
}
//save the client message
iNotifyConnMessage = RMessage2(aMessage);
//if there is an existing connection event that the client does
//not yet know about
if (iConnectionEventQueue->Count() > 0)
{
//complete straight away with package from queue
TInt err = iNotifyConnMessage.Write(KBTEngEventSlot, (*iConnectionEventQueue)[0]);
if (err == KErrNone)
{
iConnectionEventQueue->Delete(0);
}
iNotifyConnMessage.Complete(err);
}
}
break;
case EBTEngCancelEventNotifier:
{
if( !iNotifyConnMessage.IsNull() )
{
iNotifyConnMessage.Complete( KErrCancel );
}
}
break;
case EBTEngConnectDevice:
case EBTEngCancelConnectDevice:
case EBTEngDisconnectDevice:
case EBTEngIsDeviceConnected:
case EBTEngGetConnectedAddresses:
{
TBTPowerStateValue pwr = EBTPowerOff;
Server()->GetHwPowerState( pwr );
if( pwr )
{
// Simply forward it to the plug-in manager
Server()->DispatchPluginMessageL( aMessage );
}
else
{
User::Leave( KErrNotReady );
}
}
break;
case EBTEngIsDeviceConnectable:
{
Server()->DispatchPluginMessageL( aMessage );
}
break;
case EBTEngPrepareDiscovery:
{
aMessage.Complete( KErrNone ); // Client does not have to wait.
Server()->iBBConnMgr->ManageTopology( ETrue );
}
break;
case EBTEngSetPairingObserver:
case EBTEngPairDevice:
{
TBTPowerStateValue pwr = EBTPowerOff;
(void) Server()->GetHwPowerState( pwr );
if( pwr )
{
// Simply forward it to the pairing manager
Server()->PairManager().ProcessCommandL( aMessage );
if ( opcode == EBTEngPairDevice )
{
iPairMessage = RMessage2( aMessage );
}
}
else
{
User::Leave( KErrNotReady );
}
break;
}
case EBTEngCancelPairDevice:
{
CancelPairRequest();
break;
}
default:
{
TRACE_INFO( ( _L( "[BTENG]\t DispatchMessageL: bad request (%d)" ),
aMessage.Function() ) )
User::Leave( KErrArgument );
}
break;
}
TRACE_FUNC_EXIT
}
// ---------------------------------------------------------------------------
// Only the originator of pairing can cancel the pairing request.
// ---------------------------------------------------------------------------
//
void CBTEngSrvSession::CancelPairRequest()
{
if ( !iPairMessage.IsNull() )
{
Server()->PairManager().CancelCommand( iPairMessage.Function() );
iPairMessage.Complete( KErrCancel );
}
}