|
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 |