diff -r 000000000000 -r f63038272f30 bluetoothengine/bteng/btengdiscovery/src/btengsdpquery.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/bteng/btengdiscovery/src/btengsdpquery.cpp Mon Jan 18 20:28:57 2010 +0200 @@ -0,0 +1,360 @@ +/* +* 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: Helper class for performing SDP queries. +* +*/ + + + +#include + +#include "btengsdpquery.h" +#include "btengdiscovery.h" +#include "btengsdpattrparser.h" +#include "debug.h" + + +/** Array granularity for storing SDP attribute values (the number + * of attributes returned from an attribute search is expected + * to be small). + */ +const TInt KBTEngDefaultGranularity = 2; + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// C++ default constructor +// --------------------------------------------------------------------------- +// +CBTEngSdpQuery::CBTEngSdpQuery( MBTEngSdpResultReceiver* aNotifier ) +: iAttrValArray( KBTEngDefaultGranularity ), + iResultNotifier( aNotifier ) + { + } + + +// --------------------------------------------------------------------------- +// Symbian 2nd-phase constructor +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::ConstructL() + { + TRACE_FUNC_ENTRY + iParser = CBTEngSdpAttrParser::NewL( &iAttrResArray ); + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// NewL +// --------------------------------------------------------------------------- +// +CBTEngSdpQuery* CBTEngSdpQuery::NewL( MBTEngSdpResultReceiver* aNotifier ) + { + CBTEngSdpQuery* self = new( ELeave ) CBTEngSdpQuery( aNotifier ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +// +CBTEngSdpQuery::~CBTEngSdpQuery() + { + TRACE_FUNC_ENTRY + Cancel(); + delete iSdpAgent; + delete iParser; + iResultNotifier = NULL; + } + + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::Cancel() + { + TRACE_FUNC_ENTRY + if( iQueryType != EQueryIdle ) + { + // Only call the agent when a search is active, as it + // involves some cleanup which is not necessary for every call. + iSdpAgent->Cancel(); + iQueryType = EQueryIdle; + } + iRecHandleArray.Close(); + iAttrResArray.Close(); + iAttrValArray.ResetAndDestroy(); + iRequestedAttrId = 0; + } + + +// --------------------------------------------------------------------------- +// Service query +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::RemoteSdpQueryL( const TBTDevAddr& aAddr, const TUUID& aService ) + { + TRACE_FUNC_ENTRY + CheckSdpAgentL( aAddr ); + if( iQueryType == EQueryIdle ) + { + iQueryType = EServiceQuery; + iAttrResArray.Close(); + iAttrValArray.ResetAndDestroy(); + iRequestedAttrId = 0; + } + iRecHandleArray.Close(); + CSdpSearchPattern* searchPattern = CSdpSearchPattern::NewL(); + CleanupStack::PushL( searchPattern ); + searchPattern->AddL( aService ); + iSdpAgent->SetRecordFilterL( *searchPattern ); // Copies searchpattern. + iSdpAgent->NextRecordRequestL(); + CleanupStack::PopAndDestroy( searchPattern ); + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// Attribute query +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::RemoteSdpQueryL( const TBTDevAddr& aAddr, + const TSdpServRecordHandle aHandle, const TSdpAttributeID aAttrId ) + { + TRACE_FUNC_ENTRY + CheckSdpAgentL( aAddr ); + // this could be part of a ServiceSearchAttribute query. + if( iQueryType == EQueryIdle ) + { + iQueryType = EAttrQuery; + iRecHandleArray.Close(); + } + iRequestedAttrId = aAttrId; + iAttrResArray.Close(); + iAttrValArray.ResetAndDestroy(); + iSdpAgent->AttributeRequestL( aHandle, aAttrId ); + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// ServiceAttribute query +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::RemoteSdpQueryL( const TBTDevAddr& aAddr, const TUUID& aService, + const TSdpAttributeID aAttrId ) + { + TRACE_FUNC_ENTRY + if( iQueryType != EQueryIdle ) + { + User::Leave( KErrInUse ); + } + iQueryType = EServiceAttrQuery; + iRequestedAttrId = aAttrId; + iRecHandleArray.Close(); + iAttrResArray.Close(); + iAttrValArray.ResetAndDestroy(); + // First query for the requested service. + RemoteSdpQueryL( aAddr, aService ); + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// From class MSdpAgentNotifier. +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::NextRecordRequestComplete( TInt aError, + TSdpServRecordHandle aHandle, TInt aTotalRecordsCount ) + { + TRACE_FUNC_ENTRY + if( aError == KErrNone && aTotalRecordsCount > 0 ) + { + // Store the result and wait for the next. + iRecHandleArray.Append( aHandle ); + TRAP( aError, iSdpAgent->NextRecordRequestL() ); + } + else if( aError == KErrEof ) + { + // The last notification does not contain any result anymore. + if( iQueryType == EServiceAttrQuery ) + { + if( iRecHandleArray.Count() > 0 ) + { + // Request the attribute for all matching service records. + TRAP( aError, RemoteSdpQueryL( iBDAddr, iRecHandleArray[ 0 ], + iRequestedAttrId ) ); + } + else + { + // No matches, inform the client. + iQueryType = EQueryIdle; + iResultNotifier->ServiceAttributeSearchComplete( aHandle, + iAttrResArray, + aError ); + } + } + else + { + // This was a ServiceSearch, inform our client of the result. + TInt recCount = iRecHandleArray.Count(); + if( recCount > 0 ) + { + // KErrEof is used to indicate no matching records. + aError = KErrNone; + } + iQueryType = EQueryIdle; + iResultNotifier->ServiceSearchComplete( iRecHandleArray, recCount, + aError ); + } + } + NotifyError( aError ); + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// From class MSdpAgentNotifier. +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::AttributeRequestResult( TSdpServRecordHandle aHandle, + TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue ) + { + TRACE_FUNC_ENTRY + // Ownership of CSdpAttrValue is passed here. Store the object so + // that the result array can point to string values rather than + // copy them (the object is anyway already constructed). + iAttrValArray.Append( aAttrValue ); + iParser->SetAttributeID( aAttrID ); + // Adds the attribute values synchronously to the result array. + TRAP_IGNORE( aAttrValue->AcceptVisitorL( *iParser ) ); + (void) aHandle; + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// From class MSdpAgentNotifier. +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::AttributeRequestComplete( TSdpServRecordHandle aHandle, + TInt aError ) + { + TRACE_FUNC_ENTRY + if( aError ) + { + NotifyError( aError ); + return; + } + + if( iQueryType == EAttrQuery ) + { + // This was a AttributeSearch, inform our client of the result. + iQueryType = EQueryIdle; + iResultNotifier->AttributeSearchComplete( aHandle, iAttrResArray, aError ); + } + else if( iQueryType == EServiceAttrQuery ) + { + TInt index = iRecHandleArray.Find( aHandle ); + if( index <= KErrNotFound ) + { + NotifyError( KErrCorrupt ); + return; + } + // Pop the handle, since we don't need it anymore. + iRecHandleArray.Remove( index ); + if( iRecHandleArray.Count() == 0 ) + { + // This was the last result. + aError = KErrEof; + iQueryType = EQueryIdle; + } + iResultNotifier->ServiceAttributeSearchComplete( aHandle, iAttrResArray, + aError ); + if( aError != KErrEof && iQueryType == EServiceAttrQuery ) + { + // Request the attribute from the next matching record (if + // not cancelled in the callback, hence the check for the + // querytype) This will reset the attribute result array. + TRAP( aError, RemoteSdpQueryL( iBDAddr, iRecHandleArray[ 0 ], + iRequestedAttrId ) ); + NotifyError( aError ); // Does nothing if there is no error. + } + } + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::NotifyError( TInt aError ) + { + if( aError == KErrNone || aError == KErrEof || iResultNotifier == NULL ) + { + return; + } + TSdpQueryType query = iQueryType; + iQueryType = EQueryIdle; // Need to set this before calling clients, + // as they may call us straight again. + if( query == EServiceQuery ) + { + iResultNotifier->ServiceSearchComplete( RSdpRecHandleArray(), 0, aError ); + } + else if( query == EAttrQuery ) + { + iResultNotifier->AttributeSearchComplete( 0, RSdpResultArray(), aError ); + } + if( query == EServiceAttrQuery ) + { + iResultNotifier->ServiceAttributeSearchComplete( 0, RSdpResultArray(), + aError ); + } + } + + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CBTEngSdpQuery::CheckSdpAgentL( const TBTDevAddr& aAddr ) + { + if( !iSdpAgent || aAddr != iBDAddr ) + { + delete iSdpAgent; + iSdpAgent = NULL; + iBDAddr = aAddr; + iSdpAgent = CSdpAgent::NewL( *this, iBDAddr ); + } + else + { + iSdpAgent->Cancel(); + } + if( iQueryType != EQueryIdle && iQueryType != EServiceAttrQuery ) + { + // Another query is ongoing and has not been cancelled. + User::Leave( KErrInUse ); + } + }