--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btsdp/server/protocol/reqhandler.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,757 @@
+// Copyright (c) 2000-2009 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:
+//
+
+#include <bluetooth/logger.h>
+#include <btsdp.h>
+#include "reqhandler.h"
+#include "pduhandler.h"
+#include "listener.h"
+#include "sdpconsts.h"
+#include "SDPDatabase.h"
+#include "MAttributeVisitor.h"
+#include "ExtractorVisitor.h"
+#include "responsesizevisitor.h"
+#include "DataEncoder.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_SDP_SERVER);
+#endif
+
+// statics
+
+void SdpReqHandler::HandleL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
+ {
+ switch (aReqPdu.iPduId)
+ {
+ case EServiceSearchRequest:
+ HandleServiceSearchL(aDatabase, aReqPdu, aRespPdu);
+ break;
+ case EServiceAttributeRequest:
+ HandleServiceAttributeL(aDatabase, aReqPdu, aRespPdu);
+ break;
+ case EServiceSearchAttributeRequest:
+ HandleServiceSearchAttributeL(aDatabase, aReqPdu, aRespPdu);
+ break;
+ default:
+ User::Leave(KErrArgument);
+ }
+ }
+
+#ifdef __FLOGGING__
+TInt SdpReqHandler::RunError(TInt aError, const TSdpPdu& aReqPdu, TSdpPdu &aRespPdu)
+#else
+TInt SdpReqHandler::RunError(TInt aError, const TSdpPdu& /*aReqPdu*/, TSdpPdu &aRespPdu)
+#endif
+/**
+ Send an appropriate error.
+
+ Parameter format is
+ @verbatim
+ Error Code TUint16
+ Error Info Variable (0 in 1.0B)
+ @endverbatim
+**/
+ {
+ TSdpErrorCodes code;
+ switch (aError)
+ {
+ case KErrNotSupported:
+ code = EInvalidSdpVersion;
+ break;
+ case KErrBadHandle:
+ code = EInvalidServiceRecordHandle;
+ break;
+ case KErrOverflow:
+ case KErrUnderflow:
+ case KErrTooBig:
+ code = EInvalidPduSize;
+ break;
+ case KErrNotReady:
+ case KErrUnknown:
+ case KErrLocked:
+ code = EInvalidContinuationState;
+ break;
+ case KErrNoMemory:
+ case KErrHardwareNotAvailable:
+ code = EInsufficientResources;
+ break;
+ case KErrCorrupt:
+ case KErrArgument:
+ default:
+ code = EInvalidRequestSyntax;
+ break;
+ }
+ aRespPdu.iPduId = EErrorResponse;
+ aRespPdu.iParams.SetLength(2);
+ BigEndian::Put16(&aRespPdu.iParams[0], TUint16(code));
+
+ LOG1(_L("SdpReqHandler::RunError(%d)"), aError);
+
+ return KErrNone;
+ }
+
+
+void SdpReqHandler::HandleServiceSearchL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
+/**
+ Handle Service Search request.
+ Request parameter format is
+ @verbatim
+ Service search pattern DES
+ Max record handle count TUint16
+ Continuation state 1 + 0-16 bytes
+ @endverbatim
+
+ Response parameter format is
+ @verbatim
+ Total record count TUint16
+ Records in this response TUint16
+ Record handle list TUint32 * N
+ Continuation State 1 + 0-16 bytes
+ @endverbatim
+
+**/
+ {
+// Parse the request parameters
+ TPtr8 params(aReqPdu.iParams);
+ CSdpPDUHandler* pHandler = new (ELeave) CSdpPDUHandler();
+ CleanupStack::PushL(pHandler);
+ TInt maxTotalRecCount;
+ TInt len;
+ TInt rem;
+ TInt sentRecords=0;
+
+ CSizeAccumulator* collector = CSizeAccumulator::NewL();
+ CleanupStack::PushL(collector);
+
+ CSdpSearchPattern* pattern = pHandler->UUIDListLC(params, KRecHandleCountSize, len, rem, maxTotalRecCount);
+
+// first level checks for continuation parameter
+ TBool inContFlag = pHandler->ContinuationL(params, len, rem);
+
+ CResponseSizeVisitor::SizeRespSSL(aDatabase, *pattern, *collector);
+ CleanupStack::PopAndDestroy(/*pattern*/);
+
+ TInt fullSize = collector->HandleCount(); // we only have handles here
+ fullSize = Min(fullSize, maxTotalRecCount); // we may not be able to send all the handles anyway
+// TInt16 localCRC = collector->CRC(); this is for attributes
+ if (inContFlag)
+ {
+ if (fullSize != (TInt)pHandler->FullLength()) User::Leave(KErrUnknown); // continuation check
+ sentRecords = pHandler->ContinuationOffset(); // this is in count of handles, not bytes
+ if (fullSize <= sentRecords) User::Leave(KErrUnknown); // continuation check
+// if (localCRC != pHandler->ReqCRC()) User::Leave(KErrUnknown); continuation check for attributes
+ }
+ else
+ sentRecords = 0;
+
+/*
+ working out if we can send all or some of the data:
+ if there is a maxhandles outstanding, comply with that
+ if we can send all the data (handles) fine
+ if we can't send all the data, reduce the buffer by the continuation
+*/
+ TInt pduSize = fullSize - sentRecords; // the count of handles left to send
+
+ // start with the buffer size less: the minimum allocated, the total and this time handle count size and the empty continuation header
+ TInt bufferUsableLen = aRespPdu.iParams.MaxLength() - ((KRspHandleCountSize * 2) + KContStateHeader);
+
+ TBool outContFlag;
+ if (bufferUsableLen < (pduSize * KSdpRecordHandleSize))
+ {// has to be a continuation
+ outContFlag = ETrue;
+ bufferUsableLen -= KSdpContinuationStateLength; // we need the header now
+/*
+ when sending attributes (AR, SAS) make sure we don't leave a single byte
+ to be sent in the next continuation. Otherwise, reduce the payload this
+ time by 1 to make sure we comply with the specification and send a minimum
+ of two bytes in the response.
+*/
+ }
+ else
+ {
+ outContFlag = EFalse;
+// we can complete this request this time
+ }
+
+ TUint handleCount = bufferUsableLen >> 2; // get the length in handle speak
+ pduSize = Min(pduSize, handleCount);
+
+// end of common second stage continuation processing
+
+ // Write the response packet
+ aRespPdu.iPduId = EServiceSearchResponse;
+ aRespPdu.iParams.SetMax();
+ TPtr8 responseHandles(0,0);
+ responseHandles.Set(&aRespPdu.iParams[0], 0, aRespPdu.iParams.MaxLength());
+ TInt oldLen = responseHandles.Length(); // erm, zero
+ responseHandles.SetLength(oldLen + (KRspHandleCountSize * 2));
+ BigEndian::Put16(&responseHandles[KRspTotalCountOffset], (TUint16)fullSize);
+ BigEndian::Put16(&responseHandles[KRspHandleCountOffset], (TUint16)pduSize);
+ for (TInt i = 0; i < pduSize; i++)
+ {
+ oldLen = responseHandles.Length();
+ responseHandles.SetLength(oldLen + KSdpRecordHandleSize);
+ BigEndian::Put32(&responseHandles[oldLen], collector->HandleAt(sentRecords+i));
+ }
+ oldLen = responseHandles.Length();
+ if (outContFlag)
+ {
+ responseHandles.SetLength(oldLen + KSdpContinuationStateLength + KContStateHeader);
+ responseHandles[oldLen] = KSdpContinuationStateLength;
+ BigEndian::Put32(&responseHandles[oldLen + KContContOff + KContStateHeader], (sentRecords + pduSize));
+ BigEndian::Put32(&responseHandles[oldLen + KContTotOff + KContStateHeader], fullSize);
+ BigEndian::Put16(&responseHandles[oldLen + KContCrcOff + KContStateHeader], 0); // CRC not used
+ }
+ else
+ {
+ responseHandles.SetLength(oldLen + KContStateHeader);
+ responseHandles[oldLen] = 0;
+ }
+ aRespPdu.iParams.SetLength(responseHandles.Length());
+ CleanupStack::PopAndDestroy(2 /*collector, pHandler*/);
+ }
+
+
+void SdpReqHandler::HandleServiceAttributeL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
+/**
+ Handle Service Attribute request.
+ Request parameter format is
+ @verbatim
+ Service record handle TUint32
+ Max Attribute byte count TUint16
+ Attribute ID/range list DES
+ Continuation state 1 + 0-16 bytes
+ @endverbatim
+
+ Response parameter format is
+ @verbatim
+ byte count of attr list TUint16
+ Attribute ID & Value DES
+ Continuation State 1 + 0-16 bytes
+ @endverbatim
+
+**/
+ {
+// Parse the request parameters
+ TPtr8 fullParams(aReqPdu.iParams);
+ if (fullParams.Length() < KRecAttribListOffset)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ TPtrC8 params = fullParams.Right(fullParams.Length() - KRecAttribListOffset);
+ TInt len = params.Length();
+ TInt rem;
+ TInt sentRecords=0;
+ TInt sentAttributes=0;
+
+ CSdpPDUHandler* pHandler = new (ELeave) CSdpPDUHandler();
+ CleanupStack::PushL(pHandler);
+ CSizeAccumulator* collector = CSizeAccumulator::NewL();
+ CleanupStack::PushL(collector);
+
+
+// record handle to search
+ TSdpServRecordHandle recordHandle = BigEndian::Get32(&fullParams[KRecHandleOffset]);
+// maximum byte count for results
+ TInt maxTotalAttributeCount = BigEndian::Get16(&fullParams[KAttributeCountOffset]);
+
+// list of Attributes or ranges
+ CSdpAttrIdMatchList *attMatchList = pHandler->AttrListLC(params, rem);
+// check for the continuation header
+ TBool inContFlag = pHandler->ContinuationL(params, len, rem);
+// find the record
+ CSdpServRecord* theRecord=0;
+// changed to allow testing with Tsdpdp.cpp
+ for(TServRecordIter recIter(aDatabase.RecordIter()); recIter; recIter++)
+ {// Iterate thru records in Db
+ if ((*recIter).Handle() == recordHandle)
+ {
+ theRecord = recIter;
+ break;
+ }
+ }
+// record not found
+ if (!theRecord) User::Leave(KErrBadHandle);
+
+// size the response
+ CResponseSizeVisitor::SizeRespARL(*theRecord, *attMatchList, *collector);
+ CleanupStack::PopAndDestroy(/*attMatchList*/);
+// should only have one record in the size list
+ if (collector->HandleCount() != 1) User::Leave(KErrArgument);
+
+// some checks on continuation
+ TUint fullSize = collector->SizeLeft(); // we can always send all bytes the max is only per PDU
+// the sizer includes the DES size, but we need the record size less the header
+// NOTE in the SAS case we have a set (DES) of DES, but no DES header in front of them.
+ TUint innerRecSize = collector->HandleSize(0); // should be totalSize less the DES
+ TInt desSize = CSdpPDUHandler::DesSize(innerRecSize);
+ if (fullSize == 0) fullSize += desSize; // give it the smallest header if there are no attributes
+ TInt16 localCRC=0;
+ TUint sentBytes;
+ TUint sentBytesCurAttr; // bytes left to send on current attribute
+ if (inContFlag)
+ {
+ if (fullSize != pHandler->FullLength()) User::Leave(KErrUnknown); // continuation check
+ sentBytes = pHandler->ContinuationOffset(); // this is in bytes, not handles like service search
+ if (fullSize <= sentBytes) User::Leave(KErrUnknown); // continuation check
+// FIXME removed CRC handling until continuation works
+// localCRC = collector->CrcAttribs(); // CRC is only for attributes
+ if (localCRC != pHandler->ReqCRC()) User::Leave(KErrUnknown); // continuation check for attributes
+// collector->StartAt uses the bytes already sent to discover how far through an
+// attribute we are at the beginning of a new pdu in a continued response
+ TBool adj = collector->StartAt(sentBytes, sentBytesCurAttr, sentRecords, sentAttributes); // this is for attributes
+ if (!adj) User::Leave(KErrUnknown);
+ }
+ else
+ {
+ sentBytes = 0;
+ sentBytesCurAttr = 0;
+ }
+/*
+ working out if we can send all or some of the data:
+ if there is a maxbytes outstanding, comply with that
+ if we can send all the data (bytes) fine
+ if we can't send all the data, reduce the buffer by the continuation
+*/
+ TInt pduSize = fullSize - sentBytes; // the data left to send
+
+// start with the buffer size less:
+// the byte count size and the empty continuation header
+ TInt bufferUsableLen = aRespPdu.iParams.MaxLength() - (KRspAttributeCountSize + KContStateHeader);
+ TInt bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen);
+
+ TBool outContFlag;
+ if (bufferThisSize < pduSize)
+ {
+ outContFlag = ETrue;
+ bufferUsableLen -= KSdpContinuationStateLength; // we need the header now
+ bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen); // again the smallest
+// when sending attributes (AR, SAS) make sure we don't leave a single byte
+// to be sent in the next continuation. Otherwise, reduce the payload this
+// time by 1 to make sure we comply with the specification and send a minimum
+// of two bytes in the response.
+ if ((pduSize - bufferThisSize) == 1) bufferThisSize -= 1;
+ if (!inContFlag)
+ {
+// FIXME CRC removed until continuation works
+// localCRC = collector->CrcAttribs();
+ }
+ }
+ else
+ {
+ outContFlag = EFalse;
+// we can complete this request this time
+ }
+
+ pduSize = Min(pduSize, bufferThisSize);
+
+// end of common second stage continuation processing
+
+ TInt writtenSize = pduSize; // we will be reducing the pduSize
+
+// Write the response packet
+ aRespPdu.iPduId = EServiceAttributeResponse;
+ aRespPdu.iParams.SetMax();
+ TPtr8 responseAttributes(0,0);
+ responseAttributes.Set(&aRespPdu.iParams[0], 0, aRespPdu.iParams.MaxLength());
+ TElementEncoder attributeEncoder(responseAttributes);
+ TInt oldLen = responseAttributes.Length();
+ responseAttributes.SetLength(oldLen + KRspAttributeCountSize);
+ BigEndian::Put16(&responseAttributes[KRspAttributeCountOffset], (TUint16)(pduSize));
+ CAttrSizeItem* currentAttItem = collector->AttributeOf(sentRecords, sentAttributes);
+ TInt lastAttr = collector->AttrCount(sentRecords);
+ TPtrC8 attrValPtr(0,0);
+ TBuf8<1> wBuffer(1); // used for byte insertion
+ if (!inContFlag)
+ {// write the outer DES
+ attributeEncoder.WriteDES(innerRecSize);
+ pduSize -= desSize;
+ }
+ else
+ { // we are writing a continuation so straight into attribute data
+ if (sentBytesCurAttr)
+ { // we have to write the rest of a previous attribute
+ TPtrC8 partPtr(0,0);
+ attrValPtr.Set(currentAttItem->Attr()->Value().Des());
+ TInt unsentBytes = attrValPtr.Length() + KAttributeIdSize - sentBytesCurAttr;
+ switch(sentBytesCurAttr)
+ { // we may have to send some of the attribute ID
+ case 1:
+ // Append most significant byte to responseAttributes
+ wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize--;
+ unsentBytes--;
+ // No break statement is deliberate because we want to append
+ // the least significant byte to responseAttributes too
+ case 2:
+ wBuffer[0] = (TUint8)(currentAttItem->AttID() & 0xff);
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize--;
+ unsentBytes--;
+ partPtr.Set(attrValPtr); // it's a whole pointer
+ break;
+ default:
+ partPtr.Set(attrValPtr.Right(unsentBytes));
+ break;
+ }
+ if (unsentBytes - pduSize > 0)
+ {// we don't even get to send one complete attribute...
+ partPtr.Set(partPtr.Left(pduSize)); // adjust the size of the des we send.
+ pduSize = 0;
+ }
+ else
+ {
+ pduSize -= unsentBytes;
+ sentAttributes++;
+ }
+ attributeEncoder.WriteDesc(partPtr);
+ }
+ // what should be here ?
+ }
+// now send bytes up to what's left of pduSize
+ TInt currentAttr = sentAttributes;
+ TInt attrSize;
+ while (pduSize > 0 && currentAttr < lastAttr)
+ {
+ if (currentAttr > lastAttr) User::Leave(KErrUnknown); // should go past the last attribute
+ currentAttItem = collector->AttributeOf(sentRecords, currentAttr);
+ if (pduSize < 3)
+ {
+ wBuffer[0] = KAttrIdHeader;
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize--;
+ if (pduSize == 0) break;
+ }
+ if (pduSize == 1)
+ {
+ wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize = 0;
+ break;
+ }
+ attributeEncoder.WriteUint(currentAttItem->AttID(), 2);
+ pduSize -= KAttributeIdSize; // the attrID with its header
+ if (pduSize == 0) break;
+ attrSize = currentAttItem->Size();
+ attrValPtr.Set(currentAttItem->Attr()->Value().Des());
+ if (attrSize > pduSize)
+ {
+ TPtrC8 partPtr;
+ partPtr.Set(attrValPtr.Left(pduSize));
+ attributeEncoder.WriteDesc(partPtr);
+ pduSize = 0;
+ }
+ else
+ {
+ attributeEncoder.WriteDesc(attrValPtr);
+ pduSize -= attrSize;
+ }
+ currentAttr++;
+ }
+ oldLen = responseAttributes.Length();
+ if (outContFlag)
+ {
+ responseAttributes.SetLength(oldLen + KSdpContinuationStateLength + KContStateHeader);
+ responseAttributes[oldLen] = KSdpContinuationStateLength;
+ BigEndian::Put32(&responseAttributes[oldLen + KContContOff + KContStateHeader], (sentBytes + writtenSize));
+ BigEndian::Put32(&responseAttributes[oldLen + KContTotOff + KContStateHeader], fullSize);
+ BigEndian::Put16(&responseAttributes[oldLen + KContCrcOff + KContStateHeader], localCRC); // CRC not used
+ }
+ else
+ {
+ responseAttributes.SetLength(oldLen + KContStateHeader);
+ responseAttributes[oldLen] = 0;
+ }
+ aRespPdu.iParams.SetLength(responseAttributes.Length());
+ CleanupStack::PopAndDestroy(2 /*collector, pHandler*/);
+ }
+
+void SdpReqHandler::HandleServiceSearchAttributeL(CSdpDatabase &aDatabase, const TSdpPdu &aReqPdu, TSdpPdu &aRespPdu)
+/**
+ Handle Service Attribute Search request.
+ Request parameter format is
+ @verbatim
+ Service search pattern DES
+ Max Attribute byte count TUint16
+ Attribute ID/range list DES
+ Continuation state 1 + 0-16 bytes
+ @endverbatim
+
+ Response parameter format is
+ @verbatim
+ Total byte count TUint16
+ for each record matched DES of
+ Attribute ID & Value DES
+ Continuation State 1 + 0-16 bytes
+ @endverbatim
+
+**/
+ {
+// Parse the request parameters
+ TPtr8 params(aReqPdu.iParams);
+ TInt len = params.Length();
+ TInt rem;
+ TInt sentRecords=0;
+ TInt sentAttributes=0;
+ TInt maxTotalAttributeCount = 0;
+
+ CSdpPDUHandler* pHandler = new (ELeave) CSdpPDUHandler();
+ CleanupStack::PushL(pHandler);
+ CSizeAccumulator* collector = CSizeAccumulator::NewL();
+ CleanupStack::PushL(collector);
+
+
+ CSdpSearchPattern* pattern = pHandler->UUIDListLC(params, KRecHandleCountSize, len, rem, maxTotalAttributeCount);
+
+// list of Attributes or ranges
+ TPtrC8 attrParams = params.Right(rem);
+ CSdpAttrIdMatchList *attMatchList = pHandler->AttrListLC(attrParams, rem);
+// check for the continuation header
+ TBool inContFlag = pHandler->ContinuationL(params, len, rem);
+// size the response
+ CResponseSizeVisitor::SizeRespSAL(aDatabase, *pattern, *attMatchList, *collector);
+ CleanupStack::PopAndDestroy(2 /*attMatchList, pattern*/);
+ TInt totalHandles = collector->HandleCount();
+
+// some checks on continuation
+ TUint fullSize = collector->SizeLeft(); // we can always send all bytes the max is only per PDU
+// the sizer includes the DES size, but we need the record size less the header
+// NOTE in the SAS case we have a set (DES) of DES, but no DES header in front of them.
+ TInt desSize = CSdpPDUHandler::DesSize(fullSize);// the DES of DES length is not calculated by SizeLeft
+ fullSize += desSize; // this avoids the case of zero attributes
+ TInt16 localCRC = 0;
+ TUint sentBytes;
+ TUint sentBytesCurAttr; // bytes on current attribute already sent
+ if (inContFlag)
+ {
+ if (fullSize != pHandler->FullLength()) User::Leave(KErrUnknown); // continuation check
+ sentBytes = pHandler->ContinuationOffset(); // this is in bytes, not handles like service search
+ if (fullSize <= sentBytes) User::Leave(KErrUnknown); // continuation check
+
+// FIXME removed CRC handling until continuation works
+// localCRC = collector->CrcAttribs(); // CRC is only for attributes
+ if (localCRC != pHandler->ReqCRC()) User::Leave(KErrUnknown); // continuation check for attributes
+
+// collector->StartAt uses the bytes already sent to discover how far through an
+// attribute we are at the beginning of a new pdu in a continued response....
+// ....in SAS we need to remove the desSize from any sent bytes as the outer DES is not
+// counted in StartAt.
+// ....also NOTE: because further down we ensure that no new record DES or part thereof)
+// is sent at the end of a pdu any non-zero value returned in sentBytesCurAttr will not be
+// just that (bytes already sent of current attribute split in process of continuation)
+ TBool adj = collector->StartAt(sentBytes - desSize, sentBytesCurAttr, sentRecords, sentAttributes); // this is for attributes
+ if (!adj) User::Leave(KErrUnknown);
+ }
+ else
+ {
+ sentBytes = 0;
+ sentBytesCurAttr = 0;
+ }
+
+/*
+ working out if we can send all or some of the data:
+ if there is a maxbytes outstanding, comply with that
+ if we can send all the data (bytes) fine
+ if we can't send all the data, reduce the buffer by the continuation
+ and then take the minimum of the maxbytes or what is left of the buffer
+*/
+ TInt pduSize = fullSize - sentBytes; // the data left to send
+
+// start with the buffer size less:
+// the byte count size and the empty continuation header
+ TInt bufferUsableLen = aRespPdu.iParams.MaxLength() - (KRspAttributeCountSize + KContStateHeader);
+ TInt bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen);
+
+ TBool outContFlag;
+ if (bufferThisSize < pduSize)
+ {
+ outContFlag = ETrue;
+ bufferUsableLen -= KSdpContinuationStateLength; // we need the header now
+ bufferThisSize = Min(maxTotalAttributeCount, bufferUsableLen); // again the smallest
+// when sending attributes (AR, SAS) make sure we don't leave a single byte
+// to be sent in the next continuation. Otherwise, reduce the payload this
+// time by 1 to make sure we comply with the specification and send a minimum
+// of two bytes in the response.
+ if ((pduSize - bufferThisSize) == 1) bufferThisSize -= 1;
+ if (!inContFlag)
+ {
+// FIXME CRC removed until continuation works
+// localCRC = collector->CrcAttribs();
+ }
+ }
+ else
+ {
+ outContFlag = EFalse;
+// we can complete this request this time
+ }
+
+ pduSize = Min(pduSize, bufferThisSize);
+
+// end of common second stage continuation processing
+
+ TInt writtenSize = pduSize; // we will be reducing the pduSize
+
+// Write the response packet
+ aRespPdu.iPduId = EServiceSearchAttributeResponse;
+ aRespPdu.iParams.SetMax();
+ TPtr8 responseAttributes(0,0); //used to point along aRespPdu.iParams, and manage this
+ responseAttributes.Set(&aRespPdu.iParams[0], 0, aRespPdu.iParams.MaxLength());
+ //NB attributeEncoder below writes to responseAttributes (pointing at response PDU)...
+ TElementEncoder attributeEncoder(responseAttributes);
+ TInt oldLen = responseAttributes.Length();
+ responseAttributes.SetLength(oldLen + KRspAttributeCountSize);
+ BigEndian::Put16(&responseAttributes[KRspAttributeCountOffset], (TUint16)(pduSize));
+ CAttrSizeItem* currentAttItem = collector->AttributeOf(sentRecords, sentAttributes);
+ TInt lastAttr = collector->AttrCount(sentRecords);
+ TPtrC8 attrValPtr(0,0);
+ TBuf8<1> wBuffer(1); // used for byte insertion
+ if (!inContFlag)
+ {// write the outer DES
+ attributeEncoder.WriteDES(fullSize - desSize);
+ pduSize -= desSize;
+ }
+ else
+ { // we are writing a continuation so straight into attribute data
+ if (sentBytesCurAttr)
+ { // we have to write the rest of a previous attribute
+ TPtrC8 partPtr(0,0);
+ attrValPtr.Set(currentAttItem->Attr()->Value().Des());
+ TInt unsentBytes = attrValPtr.Length() + KAttributeIdSize - sentBytesCurAttr;
+ switch(sentBytesCurAttr)
+ { // we may have to send some of the attribute ID
+ // coverity[unterminated_case]
+ case 1:
+ wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize--;
+ unsentBytes--;
+ // coverity[fallthrough]
+ case 2:
+ wBuffer[0] = (TUint8)(currentAttItem->AttID() & 0xff);
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize--;
+ unsentBytes--;
+ partPtr.Set(attrValPtr); // it's a whole pointer
+ break;
+ default:
+ partPtr.Set(attrValPtr.Right(unsentBytes));
+ break;
+ }
+ if (unsentBytes - pduSize > 0)
+ {// we don't even get to send one complete attribute...
+ partPtr.Set(partPtr.Left(pduSize)); // adjust the size of the des we send.
+ pduSize = 0;
+ }
+ else
+ {
+ pduSize -= unsentBytes;
+ sentAttributes++;
+ }
+ attributeEncoder.WriteDesc(partPtr);
+ }
+ // what should be here ?
+ }
+// now send bytes up to what's left of pduSize
+ TInt currentAttr = sentAttributes;
+ TInt currentRec = sentRecords;
+ TInt attrSize;
+ while (pduSize > 0 && currentRec < totalHandles)
+ { // for all handles
+ if (currentAttr == 0)
+ { // write the DES header for this list of attributes
+ TUint lRecordSize = collector->HandleSize(currentRec);
+ TInt lDesSize = CSdpPDUHandler::DesSize(lRecordSize);
+ if (pduSize <= lDesSize)
+ { // a new record DES: don't write it if it or part of it would
+ // come on the end of the data part of a pdu - leave it
+ // for the next pdu
+ writtenSize -= pduSize;
+ BigEndian::Put16(&responseAttributes[KRspAttributeCountOffset], (TUint16)(writtenSize));
+ pduSize = 0;
+ break;
+ }
+ if(lRecordSize)
+ {//only if record has any attributes to return
+ //(=> lastAttr will be > 0 when calculated below)
+ attributeEncoder.WriteDES(lRecordSize);
+ pduSize -= lDesSize;
+ }
+ }
+ lastAttr = collector->AttrCount(currentRec);
+ while (pduSize > 0 && currentAttr < lastAttr)
+ { // for all attributes
+ currentAttItem = collector->AttributeOf(currentRec, currentAttr);
+ //if clauses below put part of attribute id on the end of a pdu
+ if (pduSize < 3)
+ {
+ wBuffer[0] = KAttrIdHeader;
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize--;
+ if (pduSize == 0) break;
+ }
+ if (pduSize == 1)
+ {
+ wBuffer[0] = (TUint8)(currentAttItem->AttID() >> 8);
+ responseAttributes.Append(&wBuffer[0], 1);
+ pduSize = 0;
+ break;
+ }
+ //if we've got here we can at least write a complete attr id onto the pdu
+ attributeEncoder.WriteUint(currentAttItem->AttID(), 2);
+ pduSize -= KAttributeIdSize; // the attrID with its header
+ if (pduSize == 0) break;
+ attrSize = currentAttItem->Size();
+ attrValPtr.Set(currentAttItem->Attr()->Value().Des());
+ if (attrSize > pduSize)
+ {
+ TPtrC8 partPtr;
+ partPtr.Set(attrValPtr.Left(pduSize)); //from left pduSize bytes
+ attributeEncoder.WriteDesc(partPtr);
+ pduSize = 0;
+ }
+ else
+ {
+ attributeEncoder.WriteDesc(attrValPtr);
+ pduSize -= attrSize;
+ }
+ currentAttr++;
+ }
+ if (pduSize == 0) break;
+ currentRec++;
+ currentAttr = 0;
+ }
+ oldLen = responseAttributes.Length();
+ if (outContFlag)
+ {
+ responseAttributes.SetLength(oldLen + KSdpContinuationStateLength + KContStateHeader);
+ responseAttributes[oldLen] = KSdpContinuationStateLength;
+ BigEndian::Put32(&responseAttributes[oldLen + KContContOff + KContStateHeader], (sentBytes + writtenSize));
+ BigEndian::Put32(&responseAttributes[oldLen + KContTotOff + KContStateHeader], fullSize);
+ BigEndian::Put16(&responseAttributes[oldLen + KContCrcOff + KContStateHeader], localCRC); // CRC not used
+ }
+ else
+ {
+ responseAttributes.SetLength(oldLen + KContStateHeader);
+ responseAttributes[oldLen] = 0;
+ }
+ aRespPdu.iParams.SetLength(responseAttributes.Length());
+ CleanupStack::PopAndDestroy(2 /*collector, pHandler*/);
+ }
+
+
+
+