bluetooth/btsdp/server/protocol/reqhandler.cpp
changeset 0 29b1cd4cb562
child 51 20ac952a623c
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 <bluetooth/logger.h>
       
    17 #include <btsdp.h>
       
    18 #include "reqhandler.h"
       
    19 #include "pduhandler.h"
       
    20 #include "listener.h"
       
    21 #include "sdpconsts.h"
       
    22 #include "SDPDatabase.h"
       
    23 #include "MAttributeVisitor.h"
       
    24 #include "ExtractorVisitor.h"
       
    25 #include "responsesizevisitor.h"
       
    26 #include "DataEncoder.h"
       
    27 
       
    28 #ifdef __FLOG_ACTIVE
       
    29 _LIT8(KLogComponent, LOG_COMPONENT_SDP_SERVER);
       
    30 #endif
       
    31 
       
    32 // statics
       
    33 
       
    34 void SdpReqHandler::HandleL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
       
    35 	{
       
    36 	switch (aReqPdu.iPduId)
       
    37 		{
       
    38 	case EServiceSearchRequest: 
       
    39 		HandleServiceSearchL(aDatabase, aReqPdu, aRespPdu);
       
    40 		break;
       
    41 	case EServiceAttributeRequest:
       
    42 		HandleServiceAttributeL(aDatabase, aReqPdu, aRespPdu);
       
    43 		break;
       
    44 	case EServiceSearchAttributeRequest:
       
    45 		HandleServiceSearchAttributeL(aDatabase, aReqPdu, aRespPdu);
       
    46 		break;
       
    47 	default:
       
    48 		User::Leave(KErrArgument);
       
    49 		}
       
    50 	}
       
    51 
       
    52 #ifdef __FLOGGING__
       
    53 TInt SdpReqHandler::RunError(TInt aError, const TSdpPdu& aReqPdu, TSdpPdu &aRespPdu)
       
    54 #else
       
    55 TInt SdpReqHandler::RunError(TInt aError, const TSdpPdu& /*aReqPdu*/, TSdpPdu &aRespPdu)
       
    56 #endif
       
    57 /**
       
    58 	Send an appropriate error.
       
    59 
       
    60 	Parameter format is
       
    61  @verbatim
       
    62 		Error Code					TUint16
       
    63 		Error Info					Variable (0 in 1.0B)
       
    64  @endverbatim
       
    65 **/
       
    66 	{
       
    67 	TSdpErrorCodes code;
       
    68 	switch (aError)
       
    69 		{
       
    70 	case KErrNotSupported:
       
    71 		code = EInvalidSdpVersion;
       
    72 		break;
       
    73 	case KErrBadHandle:
       
    74 		code = EInvalidServiceRecordHandle;
       
    75 		break;
       
    76 	case KErrOverflow: 
       
    77 	case KErrUnderflow:
       
    78 	case KErrTooBig:
       
    79 		code = EInvalidPduSize;
       
    80 		break;
       
    81 	case KErrNotReady:
       
    82 	case KErrUnknown:
       
    83 	case KErrLocked:
       
    84 		code = EInvalidContinuationState;
       
    85 		break;
       
    86 	case KErrNoMemory:
       
    87 	case KErrHardwareNotAvailable:
       
    88 		code = EInsufficientResources;
       
    89 		break;
       
    90 	case KErrCorrupt:
       
    91 	case KErrArgument:
       
    92 	default:
       
    93 		code = EInvalidRequestSyntax;
       
    94 		break;
       
    95 		}
       
    96 	aRespPdu.iPduId = EErrorResponse;
       
    97 	aRespPdu.iParams.SetLength(2);
       
    98 	BigEndian::Put16(&aRespPdu.iParams[0], TUint16(code));
       
    99 
       
   100 	LOG1(_L("SdpReqHandler::RunError(%d)"), aError);
       
   101 	
       
   102 	return KErrNone;
       
   103 	}
       
   104 
       
   105 
       
   106 void SdpReqHandler::HandleServiceSearchL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
       
   107 /**
       
   108 	Handle Service Search request.
       
   109 	Request parameter format is
       
   110  @verbatim
       
   111 		Service search pattern		DES
       
   112 		Max record handle count		TUint16
       
   113 		Continuation state			1 + 0-16 bytes
       
   114  @endverbatim
       
   115 
       
   116 	Response parameter format is
       
   117  @verbatim
       
   118 		Total record count			TUint16
       
   119 		Records in this response	TUint16
       
   120 		Record handle list			TUint32 * N
       
   121 		Continuation State			1 + 0-16 bytes
       
   122  @endverbatim
       
   123 
       
   124 **/
       
   125 	{
       
   126 // Parse the request parameters
       
   127 	TPtr8 params(aReqPdu.iParams);
       
   128 	CSdpPDUHandler* pHandler = new 	(ELeave) CSdpPDUHandler();
       
   129 	CleanupStack::PushL(pHandler);
       
   130 	TInt maxTotalRecCount;
       
   131 	TInt len;
       
   132 	TInt rem;
       
   133 	TInt sentRecords=0;
       
   134 
       
   135 	CSizeAccumulator* collector = CSizeAccumulator::NewL();
       
   136 	CleanupStack::PushL(collector);
       
   137 
       
   138 	CSdpSearchPattern* pattern = pHandler->UUIDListLC(params, KRecHandleCountSize, len, rem, maxTotalRecCount);
       
   139 
       
   140 // first level checks for continuation parameter
       
   141 	TBool inContFlag = pHandler->ContinuationL(params, len, rem);
       
   142 
       
   143 	CResponseSizeVisitor::SizeRespSSL(aDatabase, *pattern, *collector);
       
   144 	CleanupStack::PopAndDestroy(/*pattern*/);
       
   145 
       
   146 	TInt fullSize = collector->HandleCount(); // we only have handles here
       
   147 	fullSize = Min(fullSize, maxTotalRecCount); // we may not be able to send all the handles anyway
       
   148 //	TInt16 localCRC = collector->CRC(); this is for attributes
       
   149 	if (inContFlag)
       
   150 		{
       
   151 		if (fullSize != (TInt)pHandler->FullLength()) User::Leave(KErrUnknown);	// continuation check
       
   152 		sentRecords = pHandler->ContinuationOffset(); // this is in count of handles, not bytes
       
   153 		if (fullSize <= sentRecords) User::Leave(KErrUnknown);	// continuation check
       
   154 //		if (localCRC != pHandler->ReqCRC()) User::Leave(KErrUnknown); continuation check for attributes
       
   155 		}
       
   156 	else
       
   157 		sentRecords = 0;
       
   158 
       
   159 /*
       
   160 	working out if we can send all or some of the data:
       
   161 	if there is a maxhandles outstanding, comply with that
       
   162 	if we can send all the data (handles) fine
       
   163 	if we can't send all the data, reduce the buffer by the continuation
       
   164 */
       
   165 	TInt pduSize = fullSize - sentRecords;	// the count of handles left to send
       
   166 
       
   167 	// start with the buffer size less: the minimum allocated, the total and this time handle count size and the empty continuation header
       
   168 	TInt bufferUsableLen = aRespPdu.iParams.MaxLength() - ((KRspHandleCountSize * 2) + KContStateHeader);
       
   169 
       
   170 	TBool outContFlag;
       
   171 	if (bufferUsableLen < (pduSize * KSdpRecordHandleSize)) 
       
   172 		{// has to be a continuation
       
   173 		outContFlag = ETrue;
       
   174 		bufferUsableLen -= KSdpContinuationStateLength;	// we need the header now
       
   175 /*
       
   176 	when sending attributes (AR, SAS) make sure we don't leave a single byte
       
   177 	to be sent in the next continuation. Otherwise, reduce the payload this
       
   178 	time by 1 to make sure we comply with the specification and send a minimum
       
   179 	of two bytes in the response.
       
   180 */
       
   181 		}
       
   182 	else
       
   183 		{
       
   184 		outContFlag = EFalse;
       
   185 // we can complete this request this time
       
   186 		}
       
   187 
       
   188 	TUint handleCount = bufferUsableLen >> 2;	// get the length in handle speak
       
   189 	pduSize = Min(pduSize, handleCount);
       
   190 
       
   191 // end of common second stage continuation processing
       
   192 
       
   193 	// Write the response packet
       
   194 	aRespPdu.iPduId = EServiceSearchResponse;
       
   195 	aRespPdu.iParams.SetMax();
       
   196 	TPtr8 responseHandles(0,0);
       
   197 	responseHandles.Set(&aRespPdu.iParams[0], 0, aRespPdu.iParams.MaxLength());
       
   198 	TInt oldLen = responseHandles.Length();	// erm, zero
       
   199 	responseHandles.SetLength(oldLen + (KRspHandleCountSize * 2));
       
   200 	BigEndian::Put16(&responseHandles[KRspTotalCountOffset], (TUint16)fullSize);
       
   201 	BigEndian::Put16(&responseHandles[KRspHandleCountOffset], (TUint16)pduSize);
       
   202 	for (TInt i = 0; i < pduSize; i++)
       
   203 		{
       
   204 		oldLen = responseHandles.Length();
       
   205 		responseHandles.SetLength(oldLen + KSdpRecordHandleSize);
       
   206 		BigEndian::Put32(&responseHandles[oldLen], collector->HandleAt(sentRecords+i));
       
   207 		}
       
   208 	oldLen = responseHandles.Length();
       
   209 	if (outContFlag)
       
   210 		{
       
   211 		responseHandles.SetLength(oldLen + KSdpContinuationStateLength + KContStateHeader);
       
   212 		responseHandles[oldLen] = KSdpContinuationStateLength;
       
   213 		BigEndian::Put32(&responseHandles[oldLen + KContContOff + KContStateHeader], (sentRecords + pduSize));
       
   214 		BigEndian::Put32(&responseHandles[oldLen + KContTotOff + KContStateHeader], fullSize);
       
   215 		BigEndian::Put16(&responseHandles[oldLen + KContCrcOff + KContStateHeader], 0);		// CRC not used
       
   216 		}
       
   217 	else
       
   218 		{
       
   219 		responseHandles.SetLength(oldLen + KContStateHeader);
       
   220 		responseHandles[oldLen] = 0;
       
   221 		}
       
   222 	aRespPdu.iParams.SetLength(responseHandles.Length());
       
   223 	CleanupStack::PopAndDestroy(2 /*collector, pHandler*/);
       
   224 	}
       
   225 
       
   226 
       
   227 void SdpReqHandler::HandleServiceAttributeL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
       
   228 /**
       
   229 	Handle Service Attribute request.
       
   230 	Request parameter format is
       
   231  @verbatim
       
   232 		Service record handle		TUint32
       
   233 		Max Attribute byte count	TUint16
       
   234 		Attribute ID/range list		DES
       
   235 		Continuation state			1 + 0-16 bytes
       
   236  @endverbatim
       
   237 
       
   238 	Response parameter format is
       
   239  @verbatim
       
   240 		byte count of attr list		TUint16
       
   241 		Attribute ID & Value		DES
       
   242 		Continuation State			1 + 0-16 bytes
       
   243  @endverbatim
       
   244 
       
   245 **/
       
   246 	{
       
   247 // Parse the request parameters
       
   248 	TPtr8 fullParams(aReqPdu.iParams);
       
   249 	if (fullParams.Length() < KRecAttribListOffset)
       
   250 	    {
       
   251 	    User::Leave(KErrUnderflow);
       
   252 	    }
       
   253 	
       
   254 	TPtrC8 params = fullParams.Right(fullParams.Length() - KRecAttribListOffset);
       
   255 	TInt len = params.Length();
       
   256 	TInt rem;
       
   257 	TInt sentRecords=0;
       
   258 	TInt sentAttributes=0;
       
   259 
       
   260 	CSdpPDUHandler* pHandler = new (ELeave) CSdpPDUHandler();
       
   261 	CleanupStack::PushL(pHandler);
       
   262 	CSizeAccumulator* collector = CSizeAccumulator::NewL();
       
   263 	CleanupStack::PushL(collector);
       
   264 
       
   265 
       
   266 // record handle to search
       
   267 	TSdpServRecordHandle recordHandle = BigEndian::Get32(&fullParams[KRecHandleOffset]);
       
   268 // maximum byte count for results
       
   269 	TInt maxTotalAttributeCount = BigEndian::Get16(&fullParams[KAttributeCountOffset]);
       
   270 
       
   271 // list of Attributes or ranges	
       
   272 	CSdpAttrIdMatchList *attMatchList = pHandler->AttrListLC(params, rem);
       
   273 // check for the continuation header
       
   274 	TBool inContFlag = pHandler->ContinuationL(params, len, rem);
       
   275 // find the record
       
   276 	CSdpServRecord* theRecord=0;
       
   277 // changed to allow testing with Tsdpdp.cpp
       
   278 	for(TServRecordIter recIter(aDatabase.RecordIter()); recIter; recIter++)
       
   279 	{// Iterate thru records in Db
       
   280 		if ((*recIter).Handle() == recordHandle)
       
   281 			{
       
   282 			theRecord = recIter;
       
   283 			break;
       
   284 			}
       
   285 		}
       
   286 //  record not found
       
   287 	if (!theRecord) User::Leave(KErrBadHandle);
       
   288 
       
   289 // size the response
       
   290 	CResponseSizeVisitor::SizeRespARL(*theRecord, *attMatchList, *collector);
       
   291 	CleanupStack::PopAndDestroy(/*attMatchList*/);
       
   292 // should only have one record in the size list
       
   293 	if (collector->HandleCount() != 1) User::Leave(KErrArgument);
       
   294 
       
   295 // some checks on continuation
       
   296 	TUint fullSize = collector->SizeLeft(); // we can always send all bytes the max is only per PDU
       
   297 // the sizer includes the DES size, but we need the record size less the header
       
   298 // NOTE in the SAS case we have a set (DES) of DES, but no DES header in front of them.
       
   299 	TUint innerRecSize = collector->HandleSize(0); // should be totalSize less the DES
       
   300 	TInt desSize = CSdpPDUHandler::DesSize(innerRecSize);
       
   301 	if (fullSize == 0) fullSize += desSize; // give it the smallest header if there are no attributes
       
   302 	TInt16 localCRC=0;
       
   303 	TUint sentBytes;
       
   304 	TUint sentBytesCurAttr;			// bytes left to send on current attribute
       
   305 	if (inContFlag)
       
   306 		{
       
   307 		if (fullSize != pHandler->FullLength()) User::Leave(KErrUnknown);	// continuation check
       
   308 		sentBytes = pHandler->ContinuationOffset(); // this is in bytes, not handles like service search
       
   309 		if (fullSize <= sentBytes) User::Leave(KErrUnknown);	// continuation check
       
   310 // FIXME removed CRC handling until continuation works
       
   311 //		localCRC = collector->CrcAttribs();						// CRC is only for attributes
       
   312 		if (localCRC != pHandler->ReqCRC()) User::Leave(KErrUnknown);				// continuation check for attributes
       
   313 // collector->StartAt uses the bytes already sent to discover how far through an 
       
   314 // attribute we are at the beginning of a new pdu in a continued response  
       
   315 		TBool adj = collector->StartAt(sentBytes, sentBytesCurAttr, sentRecords, sentAttributes); // this is for attributes
       
   316 		if (!adj) User::Leave(KErrUnknown);
       
   317 		}
       
   318 	else
       
   319 		{
       
   320 		sentBytes = 0;
       
   321 		sentBytesCurAttr = 0;
       
   322 		}
       
   323 /*
       
   324 	working out if we can send all or some of the data:
       
   325 	if there is a maxbytes outstanding, comply with that
       
   326 	if we can send all the data (bytes) fine
       
   327 	if we can't send all the data, reduce the buffer by the continuation
       
   328 */
       
   329 	TInt pduSize = fullSize - sentBytes;	// the data left to send
       
   330 
       
   331 // start with the buffer size less: 
       
   332 //		the byte count size and the empty continuation header
       
   333 	TInt bufferUsableLen = aRespPdu.iParams.MaxLength() - (KRspAttributeCountSize + KContStateHeader);
       
   334 	TInt bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen);
       
   335 
       
   336 	TBool outContFlag;
       
   337 	if (bufferThisSize < pduSize) 
       
   338 		{
       
   339 		outContFlag = ETrue;
       
   340 		bufferUsableLen -= KSdpContinuationStateLength;	// we need the header now
       
   341 		bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen); // again the smallest
       
   342 //	when sending attributes (AR, SAS) make sure we don't leave a single byte
       
   343 //	to be sent in the next continuation. Otherwise, reduce the payload this
       
   344 //	time by 1 to make sure we comply with the specification and send a minimum
       
   345 //	of two bytes in the response.
       
   346 		if ((pduSize - bufferThisSize) == 1) bufferThisSize -= 1;
       
   347 		if (!inContFlag)
       
   348 			{
       
   349 // FIXME CRC removed until continuation works
       
   350 //			localCRC = collector->CrcAttribs();
       
   351 			}
       
   352 		}
       
   353 	else
       
   354 		{
       
   355 		outContFlag = EFalse;
       
   356 // we can complete this request this time
       
   357 		}
       
   358 
       
   359 	pduSize = Min(pduSize, bufferThisSize);
       
   360 
       
   361 // end of common second stage continuation processing
       
   362 
       
   363 	TInt writtenSize = pduSize;  // we will be reducing the pduSize
       
   364 
       
   365 // Write the response packet
       
   366 	aRespPdu.iPduId = EServiceAttributeResponse;
       
   367 	aRespPdu.iParams.SetMax();
       
   368 	TPtr8 responseAttributes(0,0);
       
   369 	responseAttributes.Set(&aRespPdu.iParams[0], 0, aRespPdu.iParams.MaxLength());
       
   370 	TElementEncoder attributeEncoder(responseAttributes);
       
   371 	TInt oldLen = responseAttributes.Length();
       
   372 	responseAttributes.SetLength(oldLen + KRspAttributeCountSize);
       
   373 	BigEndian::Put16(&responseAttributes[KRspAttributeCountOffset], (TUint16)(pduSize));
       
   374 	CAttrSizeItem* currentAttItem = collector->AttributeOf(sentRecords, sentAttributes);
       
   375 	TInt lastAttr = collector->AttrCount(sentRecords);
       
   376 	TPtrC8 attrValPtr(0,0);
       
   377 	TBuf8<1> wBuffer(1); // used for byte insertion
       
   378 	if (!inContFlag)
       
   379 		{// write the outer DES
       
   380 		attributeEncoder.WriteDES(innerRecSize);
       
   381 		pduSize -= desSize;
       
   382 		}
       
   383 	else
       
   384 		{ // we are writing a continuation so straight into attribute data
       
   385 		if (sentBytesCurAttr)
       
   386 			{ // we have to write the rest of a previous attribute
       
   387 			TPtrC8 partPtr(0,0);
       
   388 			attrValPtr.Set(currentAttItem->Attr()->Value().Des());
       
   389 			TInt unsentBytes = attrValPtr.Length() + KAttributeIdSize - sentBytesCurAttr;
       
   390 			switch(sentBytesCurAttr)
       
   391 				{ // we may have to send some of the attribute ID
       
   392 			case 1:
       
   393 				// Append most significant byte to responseAttributes
       
   394 				wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
       
   395 				responseAttributes.Append(&wBuffer[0], 1);
       
   396 				pduSize--;
       
   397 				unsentBytes--;
       
   398 				// No break statement is deliberate because we want to append 
       
   399 				// the least significant byte to responseAttributes too
       
   400 			case 2:
       
   401 				wBuffer[0] = (TUint8)(currentAttItem->AttID() & 0xff);
       
   402 				responseAttributes.Append(&wBuffer[0], 1);
       
   403 				pduSize--;
       
   404 				unsentBytes--;
       
   405 				partPtr.Set(attrValPtr);	// it's a whole pointer
       
   406 				break;
       
   407 			default:
       
   408 				partPtr.Set(attrValPtr.Right(unsentBytes));
       
   409 				break;
       
   410 				}
       
   411 			if (unsentBytes - pduSize > 0)	
       
   412 				{// we don't even get to send one complete attribute...
       
   413 				partPtr.Set(partPtr.Left(pduSize)); // adjust the size of the des we send.
       
   414 				pduSize = 0;
       
   415 				}
       
   416 			else
       
   417 				{
       
   418 				pduSize -= unsentBytes;
       
   419 				sentAttributes++;
       
   420 				}
       
   421 				attributeEncoder.WriteDesc(partPtr);
       
   422 			}
       
   423 		// what should be here ?
       
   424 		}
       
   425 // now send bytes up to what's left of pduSize
       
   426 	TInt currentAttr = sentAttributes;
       
   427 	TInt attrSize;
       
   428 	while (pduSize > 0 && currentAttr < lastAttr)
       
   429 		{
       
   430 		if (currentAttr > lastAttr) User::Leave(KErrUnknown); // should go past the last attribute
       
   431 		currentAttItem = collector->AttributeOf(sentRecords, currentAttr);
       
   432 		if (pduSize < 3)
       
   433 			{
       
   434 			wBuffer[0] = KAttrIdHeader;
       
   435 			responseAttributes.Append(&wBuffer[0], 1);
       
   436 			pduSize--;
       
   437 			if (pduSize == 0) break;
       
   438 			}
       
   439 		if (pduSize == 1)
       
   440 			{
       
   441 			wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
       
   442 			responseAttributes.Append(&wBuffer[0], 1);
       
   443 			pduSize = 0;
       
   444 			break;
       
   445 			}
       
   446 		attributeEncoder.WriteUint(currentAttItem->AttID(), 2);
       
   447 		pduSize -= KAttributeIdSize; // the attrID with its header
       
   448 		if (pduSize == 0) break;
       
   449 		attrSize = currentAttItem->Size();
       
   450 		attrValPtr.Set(currentAttItem->Attr()->Value().Des());
       
   451 		if (attrSize > pduSize)
       
   452 			{
       
   453 			TPtrC8 partPtr;
       
   454 			partPtr.Set(attrValPtr.Left(pduSize));
       
   455 			attributeEncoder.WriteDesc(partPtr);
       
   456 			pduSize = 0;
       
   457 			}
       
   458 		else
       
   459 			{
       
   460 			attributeEncoder.WriteDesc(attrValPtr);
       
   461 			pduSize -= attrSize;
       
   462 			}
       
   463 		currentAttr++;
       
   464 		}
       
   465 	oldLen = responseAttributes.Length();
       
   466 	if (outContFlag)
       
   467 		{
       
   468 		responseAttributes.SetLength(oldLen + KSdpContinuationStateLength + KContStateHeader);
       
   469 		responseAttributes[oldLen] = KSdpContinuationStateLength;
       
   470 		BigEndian::Put32(&responseAttributes[oldLen + KContContOff + KContStateHeader], (sentBytes + writtenSize));
       
   471 		BigEndian::Put32(&responseAttributes[oldLen + KContTotOff + KContStateHeader], fullSize);
       
   472 		BigEndian::Put16(&responseAttributes[oldLen + KContCrcOff + KContStateHeader], localCRC);		// CRC not used
       
   473 		}
       
   474 	else
       
   475 		{
       
   476 		responseAttributes.SetLength(oldLen + KContStateHeader);
       
   477 		responseAttributes[oldLen] = 0;
       
   478 		}
       
   479 	aRespPdu.iParams.SetLength(responseAttributes.Length());
       
   480 	CleanupStack::PopAndDestroy(2 /*collector, pHandler*/);	
       
   481 	}
       
   482 
       
   483 void SdpReqHandler::HandleServiceSearchAttributeL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
       
   484 /**
       
   485 	Handle Service Attribute Search request.
       
   486 	Request parameter format is
       
   487  @verbatim
       
   488 		Service search pattern		DES
       
   489 		Max Attribute byte count	TUint16
       
   490 		Attribute ID/range list		DES
       
   491 		Continuation state			1 + 0-16 bytes
       
   492  @endverbatim
       
   493 
       
   494 	Response parameter format is
       
   495  @verbatim
       
   496 		Total byte count			TUint16
       
   497 		for each record matched		DES of
       
   498 		Attribute ID & Value		DES
       
   499 		Continuation State			1 + 0-16 bytes
       
   500  @endverbatim
       
   501 
       
   502 **/
       
   503 	{
       
   504 // Parse the request parameters
       
   505 	TPtr8 params(aReqPdu.iParams);
       
   506 	TInt len = params.Length();
       
   507 	TInt rem;
       
   508 	TInt sentRecords=0;
       
   509 	TInt sentAttributes=0;
       
   510 	TInt maxTotalAttributeCount = 0;
       
   511 
       
   512 	CSdpPDUHandler* pHandler = new (ELeave)	CSdpPDUHandler();
       
   513 	CleanupStack::PushL(pHandler);
       
   514 	CSizeAccumulator* collector = CSizeAccumulator::NewL();
       
   515 	CleanupStack::PushL(collector);
       
   516 
       
   517 
       
   518 	CSdpSearchPattern* pattern = pHandler->UUIDListLC(params, KRecHandleCountSize, len, rem, maxTotalAttributeCount);
       
   519 
       
   520 // list of Attributes or ranges	
       
   521 	TPtrC8 attrParams = params.Right(rem);
       
   522 	CSdpAttrIdMatchList *attMatchList = pHandler->AttrListLC(attrParams, rem);
       
   523 // check for the continuation header
       
   524 	TBool inContFlag = pHandler->ContinuationL(params, len, rem);
       
   525 // size the response
       
   526 	CResponseSizeVisitor::SizeRespSAL(aDatabase, *pattern, *attMatchList, *collector);
       
   527 	CleanupStack::PopAndDestroy(2 /*attMatchList, pattern*/);
       
   528 	TInt totalHandles = collector->HandleCount();
       
   529 
       
   530 // some checks on continuation
       
   531 	TUint fullSize = collector->SizeLeft(); // we can always send all bytes the max is only per PDU
       
   532 // the sizer includes the DES size, but we need the record size less the header
       
   533 // NOTE in the SAS case we have a set (DES) of DES, but no DES header in front of them.
       
   534 	TInt desSize = CSdpPDUHandler::DesSize(fullSize);// the DES of DES length is not calculated by SizeLeft
       
   535 	fullSize += desSize;		// this avoids the case of zero attributes
       
   536 	TInt16 localCRC = 0;
       
   537 	TUint sentBytes;
       
   538 	TUint sentBytesCurAttr;			// bytes on current attribute already sent
       
   539 	if (inContFlag)
       
   540 		{
       
   541 		if (fullSize != pHandler->FullLength()) User::Leave(KErrUnknown);	// continuation check
       
   542 		sentBytes = pHandler->ContinuationOffset(); // this is in bytes, not handles like service search
       
   543 		if (fullSize <= sentBytes) User::Leave(KErrUnknown);	// continuation check
       
   544 
       
   545 // FIXME removed CRC handling until continuation works
       
   546 //		localCRC = collector->CrcAttribs();						// CRC is only for attributes
       
   547 		if (localCRC != pHandler->ReqCRC()) User::Leave(KErrUnknown);				// continuation check for attributes
       
   548 
       
   549 // collector->StartAt uses the bytes already sent to discover how far through an 
       
   550 // attribute we are at the beginning of a new pdu in a continued response....   
       
   551 // ....in SAS we need to remove the desSize from any sent bytes as the outer DES is not
       
   552 // counted in StartAt.
       
   553 // ....also NOTE: because further down we ensure that no new record DES or part thereof)
       
   554 // is sent at the end of a pdu any non-zero value returned in sentBytesCurAttr will not be
       
   555 // just that (bytes already sent of current attribute split in process of continuation)
       
   556 		TBool adj = collector->StartAt(sentBytes - desSize, sentBytesCurAttr, sentRecords, sentAttributes); // this is for attributes
       
   557 		if (!adj) User::Leave(KErrUnknown);
       
   558 		}
       
   559 	else
       
   560 		{
       
   561 		sentBytes = 0;
       
   562 		sentBytesCurAttr = 0;
       
   563 		}
       
   564 
       
   565 /*
       
   566 	working out if we can send all or some of the data:
       
   567 	if there is a maxbytes outstanding, comply with that
       
   568 	if we can send all the data (bytes) fine
       
   569 	if we can't send all the data, reduce the buffer by the continuation
       
   570 	and then take the minimum of the maxbytes or what is left of the buffer
       
   571 */
       
   572 	TInt pduSize = fullSize - sentBytes;	// the data left to send
       
   573 
       
   574 // start with the buffer size less: 
       
   575 //		the byte count size and the empty continuation header
       
   576 	TInt bufferUsableLen = aRespPdu.iParams.MaxLength() - (KRspAttributeCountSize + KContStateHeader);
       
   577 	TInt bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen);
       
   578 
       
   579 	TBool outContFlag;
       
   580 	if (bufferThisSize < pduSize) 
       
   581 		{
       
   582 		outContFlag = ETrue;
       
   583 		bufferUsableLen -= KSdpContinuationStateLength;	// we need the header now
       
   584 		bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen); // again the smallest
       
   585 //	when sending attributes (AR, SAS) make sure we don't leave a single byte
       
   586 //	to be sent in the next continuation. Otherwise, reduce the payload this
       
   587 //	time by 1 to make sure we comply with the specification and send a minimum
       
   588 //	of two bytes in the response.
       
   589 		if ((pduSize - bufferThisSize) == 1) bufferThisSize -= 1;
       
   590 		if (!inContFlag)
       
   591 			{
       
   592 // FIXME CRC removed until continuation works
       
   593 //			localCRC = collector->CrcAttribs();
       
   594 			}
       
   595 		}
       
   596 	else
       
   597 		{
       
   598 		outContFlag = EFalse;
       
   599 // we can complete this request this time
       
   600 		}
       
   601 
       
   602 	pduSize = Min(pduSize, bufferThisSize);
       
   603 
       
   604 // end of common second stage continuation processing
       
   605 
       
   606 	TInt writtenSize = pduSize;  // we will be reducing the pduSize
       
   607 
       
   608 // Write the response packet
       
   609 	aRespPdu.iPduId = EServiceSearchAttributeResponse;
       
   610 	aRespPdu.iParams.SetMax();
       
   611 	TPtr8 responseAttributes(0,0); //used to point along aRespPdu.iParams, and manage this
       
   612 	responseAttributes.Set(&aRespPdu.iParams[0], 0, aRespPdu.iParams.MaxLength());
       
   613 	//NB attributeEncoder below writes to responseAttributes (pointing at response PDU)...
       
   614 	TElementEncoder attributeEncoder(responseAttributes);
       
   615 	TInt oldLen = responseAttributes.Length();
       
   616 	responseAttributes.SetLength(oldLen + KRspAttributeCountSize);
       
   617 	BigEndian::Put16(&responseAttributes[KRspAttributeCountOffset], (TUint16)(pduSize));
       
   618 	CAttrSizeItem* currentAttItem = collector->AttributeOf(sentRecords, sentAttributes);
       
   619 	TInt lastAttr = collector->AttrCount(sentRecords);
       
   620 	TPtrC8 attrValPtr(0,0);
       
   621 	TBuf8<1> wBuffer(1); // used for byte insertion
       
   622 	if (!inContFlag)
       
   623 		{// write the outer DES
       
   624 		attributeEncoder.WriteDES(fullSize - desSize);
       
   625 		pduSize -= desSize;
       
   626 		}
       
   627 	else
       
   628 		{ // we are writing a continuation so straight into attribute data
       
   629 		if (sentBytesCurAttr)
       
   630 			{ // we have to write the rest of a previous attribute
       
   631 			TPtrC8 partPtr(0,0);
       
   632 			attrValPtr.Set(currentAttItem->Attr()->Value().Des());
       
   633 			TInt unsentBytes = attrValPtr.Length() + KAttributeIdSize - sentBytesCurAttr;
       
   634 			switch(sentBytesCurAttr)
       
   635 				{ // we may have to send some of the attribute ID
       
   636 			// coverity[unterminated_case]
       
   637 			case 1:
       
   638 				wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
       
   639 				responseAttributes.Append(&wBuffer[0], 1);
       
   640 				pduSize--;
       
   641 				unsentBytes--;
       
   642 			// coverity[fallthrough]
       
   643 			case 2:
       
   644 				wBuffer[0] = (TUint8)(currentAttItem->AttID() & 0xff);
       
   645 				responseAttributes.Append(&wBuffer[0], 1);
       
   646 				pduSize--;
       
   647 				unsentBytes--;
       
   648 				partPtr.Set(attrValPtr); // it's a whole pointer
       
   649 				break;
       
   650 			default:
       
   651 				partPtr.Set(attrValPtr.Right(unsentBytes));
       
   652 				break;
       
   653 				}
       
   654 			if (unsentBytes - pduSize > 0)	
       
   655 				{// we don't even get to send one complete attribute...
       
   656 				partPtr.Set(partPtr.Left(pduSize)); // adjust the size of the des we send.
       
   657 				pduSize = 0;
       
   658 				}
       
   659 			else
       
   660 				{
       
   661 				pduSize -= unsentBytes;
       
   662 				sentAttributes++;
       
   663 				}
       
   664 			attributeEncoder.WriteDesc(partPtr);
       
   665 			}
       
   666 		// what should be here ?
       
   667 		}
       
   668 // now send bytes up to what's left of pduSize
       
   669 	TInt currentAttr = sentAttributes;
       
   670 	TInt currentRec = sentRecords;
       
   671 	TInt attrSize;
       
   672 	while (pduSize > 0 && currentRec < totalHandles)
       
   673 		{ // for all handles
       
   674 		if (currentAttr == 0)
       
   675 			{ // write the DES header for this list of attributes
       
   676 			TUint lRecordSize = collector->HandleSize(currentRec);
       
   677 			TInt lDesSize = CSdpPDUHandler::DesSize(lRecordSize);
       
   678 			if (pduSize <= lDesSize)
       
   679 				{ // a new record DES: don't write it if it or part of it would
       
   680 				  // come on the end of the data part of a pdu - leave it
       
   681 				  // for the next pdu
       
   682 				writtenSize -= pduSize;
       
   683 				BigEndian::Put16(&responseAttributes[KRspAttributeCountOffset], (TUint16)(writtenSize));
       
   684 				pduSize = 0;
       
   685 				break;
       
   686 				}
       
   687 			if(lRecordSize)
       
   688 				{//only if record has any attributes to return 
       
   689 				 //(=> lastAttr will be > 0 when calculated below)
       
   690 				attributeEncoder.WriteDES(lRecordSize);
       
   691 				pduSize -= lDesSize;
       
   692 				}
       
   693 			}
       
   694 		lastAttr = collector->AttrCount(currentRec);
       
   695 		while (pduSize > 0 && currentAttr < lastAttr)
       
   696 			{ // for all attributes
       
   697 			currentAttItem = collector->AttributeOf(currentRec, currentAttr);
       
   698 			//if clauses below put part of attribute id on the end of a pdu
       
   699 			if (pduSize < 3)
       
   700 				{
       
   701 				wBuffer[0] = KAttrIdHeader;
       
   702 				responseAttributes.Append(&wBuffer[0], 1);
       
   703 				pduSize--;
       
   704 				if (pduSize == 0) break;
       
   705 				}
       
   706 			if (pduSize == 1)
       
   707 				{
       
   708 				wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
       
   709 				responseAttributes.Append(&wBuffer[0], 1);
       
   710 				pduSize = 0;
       
   711 				break;
       
   712 				}
       
   713 			//if we've got here we can at least write a complete attr id onto the pdu
       
   714 			attributeEncoder.WriteUint(currentAttItem->AttID(), 2);
       
   715 			pduSize -= KAttributeIdSize; // the attrID with its header
       
   716 			if (pduSize == 0) break;
       
   717 			attrSize = currentAttItem->Size();
       
   718 			attrValPtr.Set(currentAttItem->Attr()->Value().Des());
       
   719 			if (attrSize > pduSize)
       
   720 				{
       
   721 				TPtrC8 partPtr;
       
   722 				partPtr.Set(attrValPtr.Left(pduSize)); //from left pduSize bytes
       
   723 				attributeEncoder.WriteDesc(partPtr);
       
   724 				pduSize = 0;
       
   725 				}
       
   726 			else
       
   727 				{
       
   728 				attributeEncoder.WriteDesc(attrValPtr);
       
   729 				pduSize -= attrSize;
       
   730 				}
       
   731 			currentAttr++;
       
   732 			}
       
   733 		if (pduSize == 0) break;
       
   734 		currentRec++;
       
   735 		currentAttr = 0;
       
   736 		}
       
   737 	oldLen = responseAttributes.Length();
       
   738 	if (outContFlag)
       
   739 		{
       
   740 		responseAttributes.SetLength(oldLen + KSdpContinuationStateLength + KContStateHeader);
       
   741 		responseAttributes[oldLen] = KSdpContinuationStateLength;
       
   742 		BigEndian::Put32(&responseAttributes[oldLen + KContContOff + KContStateHeader], (sentBytes + writtenSize));
       
   743 		BigEndian::Put32(&responseAttributes[oldLen + KContTotOff + KContStateHeader], fullSize);
       
   744 		BigEndian::Put16(&responseAttributes[oldLen + KContCrcOff + KContStateHeader], localCRC);		// CRC not used
       
   745 		}
       
   746 	else
       
   747 		{
       
   748 		responseAttributes.SetLength(oldLen + KContStateHeader);
       
   749 		responseAttributes[oldLen] = 0;
       
   750 		}
       
   751 	aRespPdu.iParams.SetLength(responseAttributes.Length());
       
   752 	CleanupStack::PopAndDestroy(2 /*collector, pHandler*/);	
       
   753 	}
       
   754 
       
   755 
       
   756 
       
   757