bluetooth/btsdp/agent/engine.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <es_sock.h>
       
    17 #include <btsdp.h>
       
    18 #include "engine.h"
       
    19 #include "agutil.h"
       
    20 #include "requester.h"
       
    21 #include "agtypes.h"
       
    22 #include "agconsts.h"
       
    23 #include "sdpconsts.h"
       
    24 #include "sdputil.h"
       
    25 #include "SDPDatabase.h"
       
    26 #include "SDPAttribute.h"
       
    27 #include "ExtractorVisitor.h"
       
    28 #include "BuilderVisitor.h"
       
    29 
       
    30 void AgPanic(TSdpAgPanic aCode)
       
    31 	{
       
    32 	User::Panic(_L("SdpAgent"),aCode);
       
    33 	}
       
    34 
       
    35 /** Adapter class.
       
    36 	
       
    37 	Very similar to CSdpServRecord ... this class does it
       
    38 	the right way. Perhaps CSdpServRecord should just use
       
    39 	one of these to build attributes. */
       
    40 NONSHARABLE_CLASS(CSdpAttrBuilder) : public CBase, public MSdpElementBuilder
       
    41 	{
       
    42 public:
       
    43 	CSdpAttrBuilder(MSdpAgentNotifier& aNotifier, TSdpServRecordHandle aHandle);
       
    44 	~CSdpAttrBuilder();
       
    45 
       
    46 	// MSdpElementBuilder interface definition
       
    47 	virtual MSdpElementBuilder* BuildUintL(const TDesC8& aUint);
       
    48 	virtual MSdpElementBuilder* BuildDESL();
       
    49 	virtual MSdpElementBuilder* StartListL();
       
    50 	virtual MSdpElementBuilder* EndListL();
       
    51 
       
    52 	void CompleteAttribute();
       
    53 
       
    54 private:
       
    55 	MSdpAgentNotifier& iNotifier;
       
    56 	CSdpAttr* iCurrentAttr;
       
    57 	TSdpServRecordHandle iHandle;
       
    58 	TBool iBuiltDES;
       
    59 	};
       
    60 
       
    61 CSdpAttrBuilder::CSdpAttrBuilder(MSdpAgentNotifier& aNotifier, TSdpServRecordHandle aHandle)
       
    62 	:iNotifier(aNotifier), iHandle(aHandle)
       
    63 	{
       
    64 	}
       
    65 
       
    66 CSdpAttrBuilder::~CSdpAttrBuilder()
       
    67 	{
       
    68 	delete iCurrentAttr;
       
    69 	}
       
    70 
       
    71 // MSdpElementBuilder interface definition
       
    72 MSdpElementBuilder* CSdpAttrBuilder::BuildUintL(const TDesC8& aUint)
       
    73 	{
       
    74 	if(!iBuiltDES)
       
    75 		User::Leave(KErrGeneral);
       
    76 	if (aUint.Length()!=2)
       
    77 		User::Leave(KErrSdpBadAttributeId);
       
    78 
       
    79 	CompleteAttribute();
       
    80 	TSdpAttributeID id = BigEndian::Get16(&aUint[0]);
       
    81 	iCurrentAttr = CSdpAttr::NewL(id, this);
       
    82 	return iCurrentAttr;
       
    83 	}
       
    84 
       
    85 MSdpElementBuilder* CSdpAttrBuilder::BuildDESL()
       
    86 	{// Start of attribute list
       
    87 	if(iBuiltDES)
       
    88 		User::Leave(KErrGeneral);
       
    89 	iBuiltDES = ETrue;
       
    90 	return this;
       
    91 	}
       
    92 
       
    93 MSdpElementBuilder* CSdpAttrBuilder::StartListL()
       
    94 	{// Start of attribute list
       
    95 	if(!iBuiltDES)
       
    96 		User::Leave(KErrGeneral);
       
    97 	return this;
       
    98 	}
       
    99 
       
   100 MSdpElementBuilder* CSdpAttrBuilder::EndListL()
       
   101 	{
       
   102 	if(!iBuiltDES)
       
   103 		User::Leave(KErrGeneral);
       
   104 	CompleteAttribute();
       
   105 	return this;
       
   106 	}
       
   107 
       
   108 void CSdpAttrBuilder::CompleteAttribute()
       
   109 	{
       
   110 	if(!iCurrentAttr)
       
   111 		{
       
   112 		return;
       
   113 		}
       
   114 	iNotifier.AttributeRequestResult(iHandle, iCurrentAttr->AttributeID(), iCurrentAttr->ReleaseValue());
       
   115 	delete iCurrentAttr;
       
   116 	iCurrentAttr = 0;
       
   117 	}
       
   118 
       
   119 
       
   120 /************************************************************************/
       
   121 //
       
   122 //   SDP agent client API (user friendly style)
       
   123 //
       
   124 /************************************************************************/
       
   125 		
       
   126 /**
       
   127 This virtual function allows the M- classes to be extended in future in a binary
       
   128 compatible way by providing a method that clients can override in future to
       
   129 allow extra callbacks to be made via aObject.
       
   130 */	
       
   131 EXPORT_C void MSdpAgentNotifier::MSAN_ExtensionInterfaceL(TUid /*aInterface*/, void*& aObject)
       
   132 	{
       
   133 	aObject = NULL;
       
   134 	}
       
   135 
       
   136 // API Facade
       
   137 
       
   138 EXPORT_C CSdpAgent* CSdpAgent::NewL(MSdpAgentNotifier& aNotifier, const TBTDevAddr& aDevAddr)
       
   139 /** Creates a new SDP Agent object.
       
   140 
       
   141 @param aNotifier Interface implemented by the query requester, which the agent 
       
   142 calls asynchronously to pass responses to queries
       
   143 @param aDevAddr The Bluetooth address of the remote device to query
       
   144 @return New service discovery agent
       
   145 @capability LocalServices */
       
   146 	{
       
   147 	CSdpAgent* self = CSdpAgent::NewLC(aNotifier, aDevAddr);
       
   148 	CleanupStack::Pop();
       
   149 	return self;
       
   150 	}
       
   151 
       
   152 EXPORT_C CSdpAgent* CSdpAgent::NewLC(MSdpAgentNotifier& aNotifier, const TBTDevAddr& aDevAddr)
       
   153 /** Creates a new SDP Agent object.
       
   154 
       
   155 Allocate and construct a service discovery agent, leaving the object on the 
       
   156 cleanup stack.
       
   157 
       
   158 @param aNotifier Interface implemented by the query requester, which the agent 
       
   159 calls asynchronously to pass responses to queries
       
   160 @param aDevAddr The Bluetooth address of the remote device to query
       
   161 @return New service discovery agent
       
   162 @capability LocalServices */
       
   163 	{
       
   164 	CSdpAgent* self = new(ELeave) CSdpAgent();
       
   165 	CleanupStack::PushL(self);
       
   166 	self->ConstructL(aNotifier, aDevAddr);
       
   167 	return self;
       
   168 	}
       
   169 
       
   170 
       
   171 EXPORT_C CSdpAgent::~CSdpAgent()
       
   172 /**
       
   173 **/
       
   174 /** Destructor. */
       
   175 	{
       
   176 	delete iAgentEngine;
       
   177 	}
       
   178 
       
   179 
       
   180 void CSdpAgent::ConstructL(MSdpAgentNotifier& aNotifier, TBTDevAddr aDevAddr)
       
   181 /**
       
   182 **/
       
   183 	{
       
   184 	iAgentEngine = CSdpAgentEng::NewL(aNotifier, aDevAddr);
       
   185 	}
       
   186 
       
   187 CSdpAgent::CSdpAgent()
       
   188 /**
       
   189 **/
       
   190 	{
       
   191 	}
       
   192 
       
   193 EXPORT_C void CSdpAgent::SetRecordFilterL(const CSdpSearchPattern& aUUIDFilter)
       
   194 /** Sets the classes of service to query for on the remote device.
       
   195 
       
   196 Responses from the agent will only contain records for services that belong 
       
   197 to the classes listed in aUUIDFilter. Service classes are represented as unique 
       
   198 identifiers (UUIDs).
       
   199 
       
   200 @param aUUIDFilter A list of UUIDs that will be matched in SDP Service Search 
       
   201 Requests. The function takes a copy of the object. Any previous UUID list 
       
   202 is deleted.
       
   203 @capability LocalServices */
       
   204 	{
       
   205 	iAgentEngine->SetRecordFilterL(aUUIDFilter);
       
   206 	}
       
   207 
       
   208 EXPORT_C void CSdpAgent::SetAttributePredictorListL(const CSdpAttrIdMatchList& /*aMatchList*/)
       
   209 /** This does nothing!
       
   210 (It used to create a copy of an attribute match list supplied, and place it in the CSdpAgentEng object.)
       
   211 
       
   212 @param aMatchList Attribute - now unused
       
   213 @capability LocalServices
       
   214 @deprecated*/
       
   215 	{
       
   216 	}
       
   217 
       
   218 EXPORT_C void CSdpAgent::NextRecordRequestL()
       
   219 /** Gets a handle to the record for the next (or first) service on the remote device 
       
   220 that matches the service class filter previously set.
       
   221 
       
   222 The function is asynchronous: on completion, it calls NextRecordRequestComplete() 
       
   223 on the MSdpAgentNotifier interface passed in the NewL(). 
       
   224 
       
   225 @see MSdpAgentNotifier::NextRecordRequestComplete()
       
   226 @capability LocalServices */
       
   227 	{
       
   228 	iAgentEngine->NextRecordRequestL();
       
   229 	}
       
   230 
       
   231 EXPORT_C void CSdpAgent::AttributeRequestL(TSdpServRecordHandle aHandle, 
       
   232 										  TSdpAttributeID aAttrID)
       
   233 /** Gets the specified attribute for a remote service. 
       
   234 
       
   235 The function is asynchronous: on completion, it calls MSdpAgentNotifier::AttributeRequestComplete(). 
       
   236 
       
   237 
       
   238 If the attribute is found, the function passes it by also calling MSdpAgentNotifier::AttributeRequestResult().
       
   239 
       
   240 @param aHandle The service for which to get the attribute, specified by its 
       
   241 record handle 
       
   242 @param aAttrID The ID of the attribute to get
       
   243 @see MSdpAgentNotifier::AttributeRequestComplete()
       
   244 @see MSdpAgentNotifier::AttributeRequestResult()
       
   245 @capability LocalServices */
       
   246 	{
       
   247 	CSdpAttrIdMatchList* list = CSdpAttrIdMatchList::NewL();
       
   248 	CleanupStack::PushL(list);
       
   249 	list->AddL(TAttrRange(aAttrID));
       
   250 	iAgentEngine->AttributeRequestL(aHandle, *list);
       
   251 	CleanupStack::PopAndDestroy(list);
       
   252 	}
       
   253 
       
   254 EXPORT_C void CSdpAgent::AttributeRequestL(TSdpServRecordHandle aHandle, 
       
   255 										  const CSdpAttrIdMatchList& aMatchList)
       
   256 /** Gets the specified attributes for a remote service. 
       
   257 
       
   258 The function is asynchronous: on completion, it calls MSdpAgentNotifier::AttributeRequestComplete(). 
       
   259 
       
   260 
       
   261 The function also calls MSdpAgentNotifier::AttributeRequestResult() for each 
       
   262 attribute found.
       
   263 
       
   264 @param aHandle The service for which to get the attribute, specified by its 
       
   265 record handle 
       
   266 @param aMatchList A list of attributes to get
       
   267 @see MSdpAgentNotifier::AttributeRequestComplete()
       
   268 @see MSdpAgentNotifier::AttributeRequestResult()
       
   269 @capability LocalServices */
       
   270 	{
       
   271 	iAgentEngine->AttributeRequestL(aHandle, aMatchList);
       
   272 	}
       
   273 
       
   274 EXPORT_C void CSdpAgent::AttributeRequestL(MSdpElementBuilder* aBuilder,
       
   275 										  TSdpServRecordHandle aHandle, 
       
   276 										  TSdpAttributeID aAttrID)
       
   277 /** Gets the specified attribute for a remote service.
       
   278 
       
   279 The function is asynchronous: on completion, it calls MSdpAgentNotifier::AttributeRequestComplete(). 
       
   280 
       
   281 
       
   282 If the attribute is found, the function calls aBuilder's interface to set 
       
   283 the attribute ID and value.
       
   284 
       
   285 @param aBuilder Object implementing the MSdpElementBuilder interface. It will 
       
   286 be called with each type found in the response.
       
   287 @param aHandle The service for which to get the attribute, specified by its 
       
   288 record handle
       
   289 @param aAttrID The ID of the attribute to get
       
   290 @see MSdpAgentNotifier::AttributeRequestComplete()
       
   291 @capability LocalServices */
       
   292 	{
       
   293 	CSdpAttrIdMatchList* list = CSdpAttrIdMatchList::NewL();
       
   294 	CleanupStack::PushL(list);
       
   295 	list->AddL(TAttrRange(aAttrID));
       
   296 	iAgentEngine->AttributeRequestL(aBuilder, aHandle, *list);
       
   297 	CleanupStack::PopAndDestroy(list);
       
   298 	}
       
   299 
       
   300 EXPORT_C void CSdpAgent::AttributeRequestL(MSdpElementBuilder* aBuilder,
       
   301 										  TSdpServRecordHandle aHandle, 
       
   302 										  const CSdpAttrIdMatchList& aMatchList)
       
   303 /** Gets the specified attributes for a remote service.
       
   304 
       
   305 The function is asynchronous: on completion, it calls MSdpAgentNotifier::AttributeRequestComplete(). 
       
   306 
       
   307 
       
   308 As each attribute is found, the function calls aBuilder's interface to set 
       
   309 the attribute ID and value.
       
   310 
       
   311 @param aBuilder Object implementing the MSdpElementBuilder interface. It will 
       
   312 be called with each type found in the response.
       
   313 @param aHandle The service for which to get the attribute, specified by its 
       
   314 record handle
       
   315 @param aMatchList A list of attributes to get
       
   316 @see MSdpAgentNotifier::AttributeRequestComplete()
       
   317 @capability LocalServices */
       
   318 	{
       
   319 	iAgentEngine->AttributeRequestL(aBuilder, aHandle, aMatchList);
       
   320 	}
       
   321 
       
   322 EXPORT_C void CSdpAgent::Cancel()
       
   323 /**Attempts to cancel an SDP Agent request.
       
   324 
       
   325 Calls cancel on active objects making request.
       
   326 Resets all variables associated with a request and its state.
       
   327 
       
   328 NB The cancel operation will not, and cannot stop results from an SDP query
       
   329 being sent by the remote.
       
   330 @capability LocalServices */
       
   331 	{
       
   332 	iAgentEngine->Cancel();
       
   333 	}
       
   334 
       
   335 /************************************************************************/
       
   336 //
       
   337 //   ENGINE for SDP agent client API
       
   338 //
       
   339 /************************************************************************/
       
   340 
       
   341 
       
   342 CSdpAgentEng* CSdpAgentEng::NewL(MSdpAgentNotifier& aNotifier, TBTDevAddr aDevAddr)
       
   343 /** Creates a new SDP Agent Engine object.
       
   344 
       
   345 The SDP Agent Engine is the class for the data member of the SDP Agent
       
   346 which actually does the work. (The SDP Agent is a facade class.)
       
   347 
       
   348 @param MSdpAgentNotifier   Interface to user object that will receive
       
   349 notifiactions of agent commands completing.
       
   350 @param TBTDevAddr	Address of the remote device the SDP agent will query. */
       
   351 	{
       
   352 	CSdpAgentEng* self = new(ELeave) CSdpAgentEng(aNotifier, aDevAddr);
       
   353 	CleanupStack::PushL(self);
       
   354 	self->ConstructL();
       
   355 	CleanupStack::Pop();
       
   356 	return self;
       
   357 	}
       
   358 
       
   359 CSdpAgentEng::~CSdpAgentEng()
       
   360 /** Creates a new SDP Agent Engine object.
       
   361 
       
   362 The SDP Agent Engine is the class for the data member of the SDP Agent
       
   363 which actually does the work. (The SDP Agent is a facade class.)
       
   364 
       
   365 @param MSdpAgentNotifier   Interface to user object that will receive
       
   366 notifiactions of agent commands completing.
       
   367 @param TBTDevAddr	Address of the remote device the SDP agent will query.*/
       
   368 	{
       
   369 				
       
   370 	delete iUUIDFilter;
       
   371 	delete iMatchList;
       
   372 	delete iDefaultAttributeBuilder;
       
   373 	delete iParser;
       
   374 	delete iBuiltRecHandles;
       
   375 	
       
   376 	if (iSearchRequester)
       
   377 		{
       
   378 		iSearchRequester->Cancel();
       
   379 		delete iSearchRequester;
       
   380 		}
       
   381 	
       
   382 	if (iAttributeRequester)
       
   383 		{
       
   384 		iAttributeRequester->Cancel();
       
   385 		delete iAttributeRequester;
       
   386 		}
       
   387 	
       
   388 	iSdpSession.Close(); //DEFECT_FIX
       
   389 	}
       
   390 
       
   391 
       
   392 void CSdpAgentEng::ConstructL()
       
   393 /** Sets ip basic requirements for SDP Agent.
       
   394 
       
   395 Perform ipc connection with ESock.
       
   396 
       
   397 Create active objects which look after requests.
       
   398 
       
   399 Create a parser to parse responses. (A builder for the parser is provided at point of request.)*/
       
   400 	{
       
   401 	TInt ret=iSdpSession.Connect();
       
   402     if(ret!=KErrNone && ret!=KErrAlreadyExists)
       
   403 		User::Leave(ret);
       
   404 	//iRequester.Open(ss);
       
   405 
       
   406 	iSearchRequester = CSdpSearchRequester::NewL(iSdpSession, *this);
       
   407 	iBuiltRecHandles = new(ELeave) CArrayFixSeg<TSdpServRecordHandle>(8);
       
   408 
       
   409 	iParser = CElementParser::NewL(0);
       
   410 	iAttributeRequester = CSdpAttributeRequester::NewL(iSdpSession, *this);
       
   411 	}
       
   412 
       
   413 CSdpAgentEng::CSdpAgentEng(MSdpAgentNotifier& aNotifier, TBTDevAddr aDevAddr)
       
   414 :iCancelCalled(EFalse),
       
   415  iNotifier(aNotifier),
       
   416  iRemoteAddress(aDevAddr)
       
   417  
       
   418 
       
   419 /** Constructor: caches the results notifier and the remote device address to be used.*/
       
   420 	{
       
   421 	}
       
   422 
       
   423 void CSdpAgentEng::SetRecordFilterL(const CSdpSearchPattern& aUUIDFilter)
       
   424 /** This function creates a new COPY of a UUID filter from the UUID filter
       
   425 supplied, and places it in the CSdpAgentEng object.
       
   426 
       
   427 If an old UUID filter list exists, it will be deleted. (A UUID filter is
       
   428 a list of UUIDs that must be contained in a service record in a remote
       
   429 database if the handle of that record is to be returned by a service search.) */
       
   430 	{
       
   431 	delete iUUIDFilter;
       
   432 	iUUIDFilter = 0;
       
   433 	iUUIDFilter = CSdpSearchPattern::NewL();
       
   434 	for(TInt i = 0;i < aUUIDFilter.Count(); ++i)
       
   435 		{
       
   436 		TUUID uuid = aUUIDFilter.At(i);
       
   437 		iUUIDFilter->AddL(uuid);
       
   438 		}
       
   439 	iSearchRequester->Cancel();
       
   440 	iSearchRequestContState.Zero();
       
   441 	iBuiltRecHandles->Reset();
       
   442 	iServiceSearchState = EIdle;
       
   443 	}
       
   444 
       
   445 void CSdpAgentEng::NextRecordRequestL()
       
   446 /** Retrieves the next record handle from the remote server, that matches
       
   447 the UUID filter previously set by SetRecordFileterL(). On completion, 
       
   448 an upcall will occur on MSdpAgentNotifier::NextRecordRequestComplete().
       
   449 **/
       
   450 	{
       
   451 	__ASSERT_ALWAYS(iUUIDFilter, AgPanic(ESdpAgRecordFilterNotSet));
       
   452 
       
   453 	iCancelCalled = EFalse;
       
   454 	if(TryToCompleteNextRecordRequest())
       
   455 		{
       
   456 		return;
       
   457 		}
       
   458 	// Need to request some fresh results
       
   459 	iSearchRequester->SearchRequestL(iRemoteAddress,
       
   460 									 *iUUIDFilter,
       
   461 									 KSdpAgMaxResultCount, 
       
   462 									 iSearchRequestContState);
       
   463 	iServiceSearchState = ERequesting;
       
   464 	}
       
   465 
       
   466 void CSdpAgentEng::AttributeRequestL(TSdpServRecordHandle aHandle, 
       
   467 									 const CSdpAttrIdMatchList& aMatchList)
       
   468 /** Retrieve attributes from a record on the remote server.
       
   469 
       
   470 On completion, an up call on MSdpAgentNotifier::AttributeRequestComplete 
       
   471 will occur. Each attribute found will be passed up through a call to 
       
   472 MSdpAgentNotifier::AttributeRequestResult.
       
   473 
       
   474 @param aHandle	Record handle to retrieve attribute from
       
   475 @param aMatchList  List Attribute IDs to retrieve. */
       
   476 
       
   477 	{
       
   478 	delete iDefaultAttributeBuilder;
       
   479 	iDefaultAttributeBuilder = 0;
       
   480 	iDefaultAttributeBuilder = new(ELeave) CSdpAttrBuilder(iNotifier, aHandle);
       
   481 	AttributeRequestL(iDefaultAttributeBuilder, aHandle, aMatchList);
       
   482 	}
       
   483 
       
   484 void CSdpAgentEng::AttributeRequestL(MSdpElementBuilder* aBuilder,
       
   485 									 TSdpServRecordHandle aHandle, 
       
   486 									 const CSdpAttrIdMatchList& aMatchList)
       
   487 /** Retrieve attributes from a record on the remote server.
       
   488 
       
   489 On completion, an up call on MSdpAgentNotifier::AttributeRequestComplete 
       
   490 will occur. As attributes are found, calls the MSdpElementBuilder
       
   491 class to describe the attribute. This will be of the form 
       
   492 n * [AttrID:AttrVal], where n is the number of attributes actually found.
       
   493 
       
   494 @param aBuilder  Class implementing MSdpElementBuilder interface to handle the result
       
   495 @param aHandle	Record handle to retrieve attribute from
       
   496 @param aMatchList  List Attribute IDs to retrieve. */
       
   497 	{
       
   498 	//Reset as appropriate
       
   499 	iCancelCalled = EFalse;
       
   500 	iAttributeRequestContState.Zero();
       
   501 	delete iMatchList;
       
   502 	iMatchList = 0;
       
   503 	iMatchList = CSdpAttrIdMatchList::NewL(aMatchList);
       
   504 	iAttributeRequestHandle = aHandle;
       
   505 	iParser->Reset(aBuilder);
       
   506 	iAttributeRequester->Cancel();
       
   507 
       
   508 	SendAttributeRequestL();
       
   509 	}
       
   510 
       
   511 void CSdpAgentEng::Cancel()
       
   512 	{
       
   513 	//Tell this object not to handle anymore upcalls (till new request is made)
       
   514 	iCancelCalled = ETrue;
       
   515 
       
   516 	//Cancel active objects
       
   517 	iSearchRequester->Cancel();
       
   518 	iAttributeRequester->Cancel();
       
   519 
       
   520 	//Reset Service Search Stuff
       
   521 	iSearchRequestContState.Zero();
       
   522 	iBuiltRecHandles->Reset();
       
   523 	iServiceSearchState = EIdle;
       
   524 	iNextRecHandle = 0;
       
   525 	iTotalRecCount = 0;
       
   526 
       
   527 	//Reset Attribute Request Stuff
       
   528 	iAttributeRequestContState.Zero();
       
   529 	}
       
   530 
       
   531 void CSdpAgentEng::HandleServiceSearchResponseL(TUint16 aTotalRecCount,
       
   532 											 TUint16 aCurrentRecCount,
       
   533 											 const TDesC8& aRecHandles,
       
   534 											 const TDesC8& aContState)
       
   535 /** Upcall from service search requester. */
       
   536 	{
       
   537 	if(iCancelCalled)
       
   538 		return;
       
   539 
       
   540 	__ASSERT_DEBUG(aCurrentRecCount * KSdpRecordHandleSize == aRecHandles.Length(),
       
   541 		AgPanic(ESdpAgServiceSearchResultError));
       
   542 	iServiceSearchState = EResultsReceived;
       
   543 	iTotalRecCount = aTotalRecCount;
       
   544 	for(TInt i = 0; i < aCurrentRecCount; ++i)
       
   545 		{
       
   546 		iBuiltRecHandles->AppendL(BigEndian::Get32(&aRecHandles[i*KSdpRecordHandleSize]));
       
   547 		}
       
   548 	iSearchRequestContState = aContState;
       
   549 
       
   550 	TryToCompleteNextRecordRequest();
       
   551 	iServiceSearchState = EResultsReceived;
       
   552 
       
   553 	}
       
   554 
       
   555 void CSdpAgentEng::HandleServiceSearchError(TInt aError)
       
   556 /** Pass service search error up to notifier - the handle supplied
       
   557 is simply a dummy ... the notifier needs to check for errors. */
       
   558 	{
       
   559 	if(iCancelCalled)
       
   560 		return;
       
   561 
       
   562 	iNotifier.NextRecordRequestComplete(aError, 0xffffffff, 0);
       
   563 	}
       
   564 
       
   565 void CSdpAgentEng::HandleAttributeResponseL(const TDesC8& aAttributeList, 
       
   566 										    const TDesC8& aContState)
       
   567 /** Up Called by Attribute Request Active Object "RunL"
       
   568 Parse out the attribute response, and handle accordingly. */
       
   569 	{
       
   570 	if(iCancelCalled)
       
   571 		return;
       
   572 	
       
   573 	TBool moreExpected = iParser->BufferedParseL(aAttributeList);
       
   574 
       
   575 	if(iDefaultAttributeBuilder && iParser->Builder() == iDefaultAttributeBuilder)
       
   576 		{// Could have just parsed an attr. Send it up (rather than wait till next iteration)
       
   577 		iDefaultAttributeBuilder->CompleteAttribute(); //calls iNotifier.AttributeRequestResult()
       
   578 		}
       
   579 
       
   580 	if (aContState.Length() == 0)
       
   581 		{
       
   582 		if (moreExpected)
       
   583 			{// Parsers not done, but we have no cont state. Oh dear.
       
   584 			User::Leave(KErrUnderflow);
       
   585 			}
       
   586 
       
   587 		iNotifier.AttributeRequestComplete(iAttributeRequestHandle, KErrNone);
       
   588 		}
       
   589 	else
       
   590 		{
       
   591 		iAttributeRequestContState = aContState;
       
   592 		SendAttributeRequestL();
       
   593 		}
       
   594 	}
       
   595 
       
   596 void CSdpAgentEng::HandleAttributeError(TInt aError)
       
   597 /**
       
   598 	Pass attribute error up to notifier.
       
   599 **/
       
   600 	{
       
   601 	if(iCancelCalled)
       
   602 		return;
       
   603 
       
   604 	iNotifier.AttributeRequestComplete(iAttributeRequestHandle, aError);
       
   605 	}
       
   606 
       
   607 void CSdpAgentEng::SendAttributeRequestL()
       
   608 /** Ask the active object which performs attribute requests to do just that.
       
   609 
       
   610 The parameters used for the request are those currently stored as data members 
       
   611 in this	object. These will have been previousfly supplied by the user.*/
       
   612 	{
       
   613 	iAttributeRequester->AttributeRequestL(iRemoteAddress, iAttributeRequestHandle,
       
   614 			KSdpAgMaxByteCount, *iMatchList, iAttributeRequestContState);
       
   615 	}
       
   616 
       
   617 TBool CSdpAgentEng::TryToCompleteNextRecordRequest()
       
   618 /** Checks whether it is necessary or not to ask remote device for more records.
       
   619 
       
   620 SdpAgent collects as many of the remote device's record handles that conform to
       
   621 the record filter as it can on each service search request sent. Thus the SdpAgent
       
   622 will only perform a fresh service search if either the record filter has been changed
       
   623 (=> iBuiltRecordHandles->Count() returns 0) or the remote device returned a non "null"
       
   624 continuation state and all the record handles currently returned by the remote device 
       
   625 have been processed.
       
   626 
       
   627 @return ETrue if NOT necessary.*/
       
   628 	{
       
   629 	if(iServiceSearchState == EResultsReceived)
       
   630 		{
       
   631 		if(iNextRecHandle < iBuiltRecHandles->Count())
       
   632 			{//We've got an answer already
       
   633 			 //N.B. The function call iNotifier.NextRecordRequestComplete must come last 
       
   634 			 //because it can call TryToCompleteNextRecordRequest() recursively.
       
   635 			iNotifier.NextRecordRequestComplete(KErrNone, iBuiltRecHandles->At(iNextRecHandle++), iTotalRecCount);
       
   636 			return ETrue;
       
   637 			}
       
   638 		else if(iSearchRequestContState.Length() == 0 || iNextRecHandle >= iTotalRecCount)
       
   639 			{// No more answers available
       
   640 			iNotifier.NextRecordRequestComplete(KErrEof, 0, 0);
       
   641 			return ETrue;
       
   642 			}
       
   643 		}
       
   644 	return EFalse;
       
   645 	}
       
   646