📄 request.c
字号:
/* Affix - Bluetooth Protocol Stack for Linux Copyright (C) 2001,2002 Nokia Corporation Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com> Original Author: Guruprasad Krishnamurthy <kgprasad@hotmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* $Id: request.c,v 1.50 2003/11/13 19:23:16 litos Exp $ Contains the SDP service discovery client request handling code. Fixes: Dmitry Kasatkin - Continuation mechanism, MTU support*/#include <affix/config.h>#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <string.h>#include <affix/sdp.h>#include <affix/sdpclt.h>#include <affix/sdpsrv.h>#include "servicedb.h"#include "utils.h"#include "attr.h"#include "cstate.h"extern void sdp_update_time(void);extern slist_t *serviceList;/* ** Search/Attribute element sequence extractor. Builds ** a slist_t whose elements are those found in the ** sequence. The data type of elements found in the ** sequence (now populated in slist_t) is returned ** in the reference pDataType */int sdp_extr_data_seq(char *pduBuffer, slist_t **svcReqSeq, uint8_t *pDataType){ int status, bytesScanned; char *pdata; uint8_t seqType; int length = 0; short numberOfElements; int seqLength; slist_t *pSeq; uint8_t dataType; bytesScanned = 0; pdata = sdp_extr_seq_dtd(pduBuffer, &seqType, &length, &bytesScanned); DBPRT("Seq type : %d", seqType); if (!pdata || (SDP_DTD_TYPE(seqType) != SDP_DTD_SEQ)) { BTERROR("Unknown seq type"); return -1; } DBPRT("Data size : %d", length); numberOfElements = 0; seqLength = 0; pSeq = NULL; for (;;) { char *pElem = NULL; int localSeqLength = 0; dataType = __get_u8(pdata); DBPRT("Data type : %d", dataType); switch (dataType) { case SDP_DTD_UINT16 : pdata += sizeof(uint8_t); seqLength += sizeof(uint8_t); pElem = (char *)malloc(sizeof(uint16_t)); if (!pElem) break; *(uint16_t *)pElem = ntohs(__get_u16(pdata)); pdata += sizeof(uint16_t); seqLength += sizeof(uint16_t); break; case SDP_DTD_UINT32 : pdata += sizeof(uint8_t); seqLength += sizeof(uint8_t); pElem = (char *)malloc(sizeof(uint32_t)); if (!pElem) break; *(uint32_t *)pElem = ntohl(__get_u32(pdata)); pdata += sizeof(uint32_t); seqLength += sizeof(uint32_t); break; case SDP_DTD_UUID16 : case SDP_DTD_UUID32 : case SDP_DTD_UUID128 : pElem = (char *)malloc(sizeof(uuid_t)); if (!pElem) break; status = __sdp_extr_uuid(pdata, (uuid_t *)pElem, &localSeqLength); if (status) { free(pElem); return status; } seqLength += localSeqLength; pdata += localSeqLength; break; } if (!pElem) continue; s_list_append(&pSeq, pElem); numberOfElements++; DBPRT("No of elements : %d", numberOfElements); if (seqLength == length) break; else if (seqLength > length) return -1; } *svcReqSeq = pSeq; bytesScanned += seqLength; *pDataType = dataType; return bytesScanned;}/* ** Service search request PDU. This methods extracts the "search pattern" ** which is a seqquence of UUIDs calls the matching function ** to find matching services */int _sdp_search_req(sdp_request_t *requestPdu, sdppdu_t *pdu){ int status = 0, i; char *pdata; int bytesScanned = 0; slist_t *searchPattern = NULL; int maxExpectedServiceRecordCount, realServiceRecordCount; uint8_t dataType; sdp_cstate_t *pCState = NULL; char *pCacheBuffer = NULL; int handleSize = 0; long cStateId = -1; short responseCount = 0; short *pTotalRecordCount; short *pCurrentRecordCount; int MTU; pdata = requestPdu->data + sizeof(sdp_hdr_t); bytesScanned = sdp_extr_data_seq(pdata, &searchPattern, &dataType); if ((bytesScanned < 0) || ((bytesScanned + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(sdp_hdr_t)) > requestPdu->len)){ status = SDP_ERR_REQUEST_SYNTAX; goto exit; } pdata += bytesScanned; maxExpectedServiceRecordCount = ntohs(__get_u16(pdata)); DBPRT("Expected count: %d", maxExpectedServiceRecordCount); DBPRT("Bytes scanned : %d", bytesScanned); pdata += sizeof(uint16_t); //bytesScanned += sizeof(uint16_t); //Fix /* ** Check if continuation state exists, if yes attempt ** to get response remainder from cache, else send error */ pCState = sdp_get_cstate(pdata); if ((pCState) && ((pCState->length + bytesScanned + sizeof(uint16_t) + sizeof(sdp_hdr_t)) > requestPdu->len)){ status = SDP_ERR_REQUEST_SYNTAX; goto exit; } MTU = requestPdu->mtu - sizeof(sdp_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - sizeof(sdp_cstate_t); realServiceRecordCount = btmin(maxExpectedServiceRecordCount, (MTU >> 2)); DBPRT("MTU: %d, realrec: %d", MTU, realServiceRecordCount); /* ** Make space in the response buffer for total ** and current record counts */ pdata = pdu->data; /* ** Total service record count = 0 */ pTotalRecordCount = (short *)pdata; __put_u16(pdata, 0); pdata += sizeof(uint16_t); pdu->length += sizeof(uint16_t); /* ** current service record count = 0 */ pCurrentRecordCount = (short *)pdata; __put_u16(pdata, 0); pdata += sizeof(uint16_t); pdu->length += sizeof(uint16_t); if (pCState == NULL) { /* ** For every element in the sdpsvc_t DB, ** do a pattern search */ int index = 0; handleSize = 0; for (;;) { void * data; sdpsvc_t *svcRec; data = s_list_nth_data(serviceList, index); if (data != NULL) { svcRec = (sdpsvc_t *)data; DBPRT("Checking svcRec : 0x%x", svcRec->serviceRecordHandle); if (sdp_match_uuid(searchPattern, svcRec->targetPattern)) { responseCount++; __put_u32(pdata, htonl(svcRec->serviceRecordHandle)); pdata += sizeof(uint32_t); handleSize += sizeof(uint32_t); } index++; } else break; } DBPRT("Match count : %d", responseCount); /* ** Add "handleSize" to pdu buffer size */ pdu->length += handleSize; __put_u16(pTotalRecordCount, htons(responseCount)); __put_u16(pCurrentRecordCount, htons(responseCount)); if (responseCount > realServiceRecordCount) { /* ** We need to cache the response and generate a ** continuation state */ cStateId = sdp_add_rsp_cscache(requestPdu->fd, pdu); /* ** Subtract the handleSize since we now send only ** a subset of handles */ pdu->length -= handleSize; } else { /* ** NULL continuation state */ sdp_set_cstate(pdu, NULL); } } /* ** Under both the conditions below, the response buffer is not ** built up yet */ if ((pCState != NULL) || (cStateId != -1)) { short lastIndex = 0; if (pCState != NULL) { sdppdu_t *pCache; /* ** Get the previous sdp_cstate_t and obtain ** the cached response */ pCache = sdp_get_rsp_cscache(requestPdu->fd, pCState); if (!pCache) { status = -1; goto exit; } pCacheBuffer = pCache->data; responseCount = ntohs(__get_u16(pCacheBuffer)); /* ** Get the index of the last sdpsvc_t sent */ lastIndex = pCState->value.lastIndexSent; } else { pCacheBuffer = pdu->data; lastIndex = 0; } /* ** Set the local buffer pointer to beyond the ** current record count. And increment the cached ** buffer pointer to beyond the counters .. */ pdata = (char *)pCurrentRecordCount + sizeof(uint16_t); /* ** There is the toatalCount and the currentCount ** fields to increment beyond */ pCacheBuffer += (2 * sizeof(uint16_t)); if (pCState == NULL) { handleSize = realServiceRecordCount << 2; //sizeof(uint32_t); i = realServiceRecordCount; } else { handleSize = 0; for (i = lastIndex; (i-lastIndex) < realServiceRecordCount && i < responseCount; i++) { __put_u32(pdata, __get_u32(((uint32_t*)pCacheBuffer) + i)); pdata += sizeof(uint32_t); handleSize += sizeof(uint32_t); } } /* ** Add "handleSize" to pdu buffer size */ pdu->length += handleSize; __put_u16(pTotalRecordCount, htons(responseCount)); __put_u16(pCurrentRecordCount, htons(i-lastIndex)); if (i == responseCount) { /* ** Set "null" continuationState & and remove it from cache */ sdp_set_cstate(pdu, NULL); sdp_del_rsp_cscache(requestPdu->fd, pCState); } else { /* ** There is more to it .. set the lastIndexSent to ** the new value and move on .. */ sdp_cstate_t newState; DBPRT("Setting non-NULL sdp_cs_t"); memset(&newState, 0, sizeof(sdp_cstate_t)); if (pCState != NULL) { memcpy(&newState, pCState, sizeof(sdp_cstate_t)); newState.value.lastIndexSent = i; } else { newState.timestamp = cStateId; newState.value.lastIndexSent = i; } sdp_set_cstate(pdu, &newState); } }exit: if (searchPattern) s_list_destroy(&searchPattern); return status;}/* ** This function generates the PDU form of a service record for ** a specified set of attributes and not the entire set. This is ** driven by a service discovery client which asks for attributes ** of a service record by speicifying a subset of attribute ** identifiers */void sdp_gen_svc_pdu_by_attr(sdpsvc_t *svcRec, uint16_t attrId, sdppdu_t *attrSubsetPDUForm){ sdpdata_t *pData; pData = (sdpdata_t*)sdp_get_attr(svcRec, attrId); if (!pData || !pData->pdu.data || !pData->pdu.length) return; sdp_append_pdu(attrSubsetPDUForm, &pData->pdu);}/* ** Extract attribute identifiers from the request PDU. ** Clients could request a subset of attributes (by id) ** from a service record, instead of the whole set. The ** requested identifiers are present in the PDU form of ** the request */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -