📄 sdpclt.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: sdpclt.c,v 1.56 2003/04/15 10:50:06 kds Exp $ Contains the implementation of the SDP service discovery API Fixes: Dmitry Kasatkin - Continuation Mechanism Dmitry Kasatkin - Port Request Dmitry Kasatkin - cleaning Dmitry Kasatkin - new simple API*/ #include <affix/config.h>#include <stdio.h>#include <stdlib.h>#include <malloc.h>#include <string.h>#include <affix/sdp.h>#include <affix/sdpclt.h>#include "utils.h"#include "cstate.h"#include "attr.h"/*** This is a service search request. **** INPUT :**** slist_t *svcSearchList** Singly linked list containing elements of the search** pattern. Each entry in the list is a uuid_t (DataTypeSDP_DTD_UUID16)** of the service to be searched**** uint16_t maxSvcRecordCount** A 16 bit integer which tells the service, the maximum** entries that the client can handle in the response. The** server is obliged not to return > maxSvcRecordCount entries**** OUTPUT :**** int return value** E_OK ** The request completed successfully. This does not** mean the requested services were found** E_FAILURE** On any failure** E_TIMEOUT ** The request completed unsuccessfully due to a timeout**** slist_t **svcHandleList** This variable is set on a successful return if there are** non-zero service handles. It is a singly linked list of** service record handles (uint32_t)**** uint16_t *handleCount** This is a pointer to a 16 bit integer, which is set to ** indicate the number of service record handles present in** svcHandleList*/int sdp_search_req( int srvHandle, slist_t *svcSearchList, uint16_t maxSvcRecordCount, slist_t **svcResponseList, uint16_t *handleCountInResponse){ int status = 0; int requestSize = 0, _requestSize; int responseSize = 0; int seqLength = 0; char *pdata, *_pdata; char *requestBuffer = NULL; char *responseBuffer = NULL; sdp_hdr_t *pduRequestHeader; sdp_hdr_t *pduResponseHeader; sdp_cs_t *pCState = NULL; //sdppdu_t concatenatedResponseBuffer; int responseLength = 0; *handleCountInResponse = 0; requestBuffer = (char *)malloc(SDP_REQ_BUF_SIZE); if (!requestBuffer) return -1; responseBuffer = (char *)malloc(SDP_RSP_BUF_SIZE); if (!responseBuffer) { free(requestBuffer); return -1; } pduRequestHeader = (sdp_hdr_t *)requestBuffer; pduRequestHeader->pduId = SDP_PDU_SEARCH_REQ; pdata = (char *)(requestBuffer + sizeof(sdp_hdr_t)); requestSize = sizeof(sdp_hdr_t); /* ** Add service class IDs for search */ seqLength = sdp_gen_uuid_seq_pdu(pdata, svcSearchList); DBPRT("Data seq added : %d\n", seqLength); /* ** Now set the length and increment the pointer */ requestSize += seqLength; pdata += seqLength; /* ** Specify the maximum svc rec count that ** client expects */ __put_u16(pdata, htons(maxSvcRecordCount)); requestSize += sizeof(uint16_t); pdata += sizeof(uint16_t); _requestSize = requestSize; _pdata = pdata; *svcResponseList = NULL; //important do { int bytesScanned = 0; int totalServiceRecordCount, currentServiceRecordCount; /* ** Add continuation state or NULL (first time) */ requestSize = _requestSize + sdp_copy_cstate(_pdata, pCState); /* ** Set the request header's param length */ pduRequestHeader->paramLength = htons(requestSize - sizeof(sdp_hdr_t)); pduRequestHeader->transactionId = htons(sdp_gen_trans()); /* ** Send the request, wait for response and if ** not error, set the appropriate values ** and return */ status = sdp_send_req_w4_rsp(srvHandle, requestBuffer, responseBuffer, requestSize, &responseSize); if (status) break; pduResponseHeader = (sdp_hdr_t *)responseBuffer; if (pduResponseHeader->pduId == SDP_PDU_ERROR_RSP) { status = pduResponseHeader->data[0]; // ErorrCode break; } responseLength = ntohs(pduResponseHeader->paramLength); pdata = responseBuffer + sizeof(sdp_hdr_t); /* ** Net service record match count */ totalServiceRecordCount = 0; currentServiceRecordCount = 0; totalServiceRecordCount = ntohs(__get_u16(pdata)); pdata += sizeof(uint16_t); bytesScanned += sizeof(uint16_t); currentServiceRecordCount = ntohs(__get_u16(pdata)); pdata += sizeof(uint16_t); bytesScanned += sizeof(uint16_t); DBPRT("Total svc count : %d\n", totalServiceRecordCount); DBPRT("Current svc count : %d\n", currentServiceRecordCount); DBPRT("ResponseLength : %d\n", responseLength); if (currentServiceRecordCount == 0) break; status = sdp_extr_svc_handles(pdata, svcResponseList, currentServiceRecordCount, &bytesScanned); if (status) break; *handleCountInResponse = currentServiceRecordCount; /* ** Check if we have sdp_cstate_t set, if yes, ** set the pCState pointer */ DBPRT("BytesScanned : %d\n", bytesScanned); if (responseLength > bytesScanned) { uint8_t cStateLength = 0; pdata = responseBuffer + sizeof(sdp_hdr_t) + bytesScanned; cStateLength = __get_u8(pdata); if (cStateLength > 0) { pCState = (sdp_cs_t *)pdata; DBPRT("Continuation state present\n"); DBPRT("sdp_cs_t length : %d\n", cStateLength); } else pCState = NULL; } } while (pCState); free(requestBuffer); free(responseBuffer); //if (concatenatedResponseBuffer.data != NULL) //free(concatenatedResponseBuffer.data); return status;}int __sdp_search_req( struct sockaddr_affix *sa, slist_t *svcSearchList, uint16_t maxSvcRecordCount, slist_t **svcResponseList, uint16_t *handleCountInResponse){ int status = 0; int srvHandle; srvHandle = sdp_connect(sa); if (srvHandle < 0) return srvHandle; status = sdp_search_req(srvHandle, svcSearchList, maxSvcRecordCount, svcResponseList, handleCountInResponse); sdp_close(srvHandle); return status;}/*** This is a service attribute request. **** INPUT :**** uint32_t svcHandle** The handle of the service for which the attribute(s) are** requested**** sdp_attrreq_t attrReqType** Attribute identifiers are 16 bit unsigned integers specified** in one of 2 ways described below :** IndividualAttributes - 16bit individual identifiers** They are the actual attribute identifiers in ascending order**** RangeOfAttributes - 32bit identifier range** The high-order 16bits is the start of range** the low-order 16bits are the end of range** 0x0000 to 0xFFFF gets all attributes**** slist_t *attrIDList** Singly linked list containing attribute identifiers desired.** Every element is either a uint16_t(attrSpec = IndividualAttributes) ** or a uint32_t(attrSpec=RangeOfAttributes)**** uint16_t maxAttrIDByteCount** The byte count of the number of attribute IDs specified** in the request list**** OUTPUT :** int return value** E_OK ** The request completed successfully. This does not** mean the requested services were found** E_TIMEOUT ** The request completed unsuccessfully due to a timeout**** uint16_t *maxAttrResponseByteCount** This is a pointer to a 16 bit integer, which is set to ** indicate the number of bytes of attributes returned. ** This pointer is set on successful return***/int sdp_attr_req( int srvHandle, uint32_t svcHandle, sdp_attrreq_t attrReqType, slist_t *attrIDList, uint16_t maxAttrIDByteCount, sdpsvc_t **_svcRec, uint16_t *maxAttrResponseByteCount){ int status = 0; int requestSize = 0, _requestSize; int responseSize = 0; int attrListByteCount = 0; int seqLength = 0; char *pdata = NULL, *_pdata; char *requestBuffer = NULL; char *responseBuffer = NULL; sdp_hdr_t *pduRequestHeader; sdp_hdr_t *pduResponseHeader; sdp_cs_t *pCState = NULL; uint8_t cStateLength = 0; sdppdu_t concatenatedResponseBuffer; sdpsvc_t *svcRec = NULL; *_svcRec = NULL; *maxAttrResponseByteCount = 0; if ((attrReqType != IndividualAttributes) && (attrReqType != RangeOfAttributes)) return SDP_ERR_INVALID_ARG; requestBuffer = (char *)malloc(SDP_REQ_BUF_SIZE); if (!requestBuffer) return SDP_ERR_INVALID_ARG; responseBuffer = (char *)malloc(SDP_RSP_BUF_SIZE); if (!responseBuffer) { free(requestBuffer); return SDP_ERR_INVALID_ARG; } memset((char *)&concatenatedResponseBuffer, 0, sizeof(sdppdu_t)); pduRequestHeader = (sdp_hdr_t *)requestBuffer; pduRequestHeader->pduId = SDP_PDU_ATTR_REQ; pdata = (char *)(requestBuffer + sizeof(sdp_hdr_t)); requestSize = sizeof(sdp_hdr_t); /* ** Add the service record handle */ __put_u32(pdata, htonl(svcHandle)); requestSize += sizeof(uint32_t); pdata += sizeof(uint32_t); /* ** Add the maxAttrIDByteCount specifying response limit */ __put_u16(pdata, htons(maxAttrIDByteCount)); requestSize += sizeof(uint16_t); pdata += sizeof(uint16_t); /* ** Get attr seq PDU form */ seqLength = sdp_gen_attr_seq_pdu(pdata, attrIDList, ((attrReqType == IndividualAttributes) ? SDP_DTD_UINT16 : SDP_DTD_UINT32)); if (seqLength < 0) { status = seqLength; goto exit; } pdata += seqLength; requestSize += seqLength; DBPRT("Attr list length : %d\n", seqLength); // save before Continuation State _pdata = pdata; _requestSize = requestSize; do { int responseCount = 0; /* ** Add NULL continuation state */ requestSize = _requestSize + sdp_copy_cstate(_pdata, pCState); /* ** Set the request header's param length */ pduRequestHeader->transactionId = htons(sdp_gen_trans()); pduRequestHeader->paramLength = htons(requestSize - sizeof(sdp_hdr_t)); status = sdp_send_req_w4_rsp(srvHandle, requestBuffer, responseBuffer, requestSize, &responseSize); if (status) goto exit; pduResponseHeader = (sdp_hdr_t *)responseBuffer; if (pduResponseHeader->pduId == SDP_PDU_ERROR_RSP) { status = pduResponseHeader->data[0]; // ErrorCode goto exit; } pdata = responseBuffer + sizeof(sdp_hdr_t); responseCount = ntohs(__get_u16(pdata)); attrListByteCount += responseCount; pdata += sizeof(uint16_t); /* ** Check if we have continuation state set, if yes, we ** need to re-issue request before we parse .. */ cStateLength = __get_u8(pdata + responseCount); DBPRT("Response id : %d\n", pduResponseHeader->pduId); DBPRT("Attrlist byte count : %d\n", responseCount); DBPRT("sdp_cs_t length : %d\n", cStateLength); /* ** This is a split response, need to concatenate the intermediate ** responses as well as the last one which will have cStateLength == 0 */ if ((cStateLength > 0) || (concatenatedResponseBuffer.length != 0)) { char *targetPtr = NULL; if (cStateLength > 0) pCState = (sdp_cs_t *)(pdata + responseCount); else pCState = NULL; /* ** Build concatenated response buffer */ concatenatedResponseBuffer.data = (char *)realloc( concatenatedResponseBuffer.data, concatenatedResponseBuffer.length + responseCount); concatenatedResponseBuffer.size = concatenatedResponseBuffer.length + responseCount; targetPtr = concatenatedResponseBuffer.data + concatenatedResponseBuffer.length; memcpy(targetPtr, pdata, responseCount); concatenatedResponseBuffer.length += responseCount; } } while (pCState); if (attrListByteCount > 0) { int bytesScanned = 0; if (concatenatedResponseBuffer.length != 0) { pdata = concatenatedResponseBuffer.data; } svcRec = sdp_clt_extr_pdu(pdata, svcHandle, &bytesScanned); DBPRT("In sdp_attr_req function \n"); DBPRT("The status of extractServiceRecord is %d\n", status); DBPRT("The svcHandle is 0x%x\n", svcHandle); if (!svcRec) { status = -1; goto exit; } *_svcRec = svcRec; *maxAttrResponseByteCount = bytesScanned; }exit: free(requestBuffer); free(responseBuffer); if (concatenatedResponseBuffer.data != NULL) free(concatenatedResponseBuffer.data); return status;}int __sdp_attr_req( struct sockaddr_affix *sa, uint32_t svcHandle, sdp_attrreq_t attrReqType, slist_t *attrIDList, uint16_t maxAttrIDByteCount, sdpsvc_t **svcRec, uint16_t *maxAttrResponseByteCount){ int status = 0; int srvHandle; srvHandle = sdp_connect(sa); if (srvHandle < 0) return srvHandle; status = sdp_attr_req(srvHandle, svcHandle, attrReqType, attrIDList, maxAttrIDByteCount, svcRec, maxAttrResponseByteCount); sdp_close(srvHandle); return status;}/*** This is a service search request combined with the service** attribute request. First a service class match is done and** for matching service, requested attributes are extracted**** INPUT :**** slist_t *svcSearchList** Singly linked list containing elements of the search** pattern. Each entry in the list is a uuid_t(DataTypeSDP_DTD_UUID16)** of the service to be searched**** AttributeSpecification attrSpec** Attribute identifiers are 16 bit unsigned integers specified** in one of 2 ways described below :** IndividualAttributes - 16bit individual identifiers** They are the actual attribute identifiers in ascending order**** RangeOfAttributes - 32bit identifier range** The high-order 16bits is the start of range** the low-order 16bits are the end of range** 0x0000 to 0xFFFF gets all attributes**** slist_t *attrIDList** Singly linked list containing attribute identifiers desired.** Every element is either a uint16_t(attrSpec = IndividualAttributes) ** or a uint32_t(attrSpec=RangeOfAttributes)**** uint16_t maxAttrIDByteCount** The byte count of the number of attribute IDs specified** in the request list**** OUTPUT :** int return value** E_OK ** The request completed successfully. This does not** mean the requested services were found** E_TIMEOUT ** The request completed unsuccessfully due to a timeout**** slist_t **svcResponseList** This variable is set on a successful return to point to** service(s) found. Each element of this list is of type** uint32_t (of the services which matched the search list)**** uint16_t *maxAttrResponseByteCount** This is a pointer to a 16 bit integer, which is set to ** indicate the number of bytes of attributes returned. ** This pointer is set on successful return***/int sdp_search_attr_req( int srvHandle, slist_t *svcSearchList, sdp_attrreq_t attrReqType, slist_t *attrIDList, uint16_t maxAttrByteCount, slist_t **svcResponseList, uint16_t *maxAttrResponseByteCount ){ int status = 0; int requestSize = 0, _requestSize; int responseSize = 0; int seqLength = 0; int attrListByteCount = 0; char *pdata = NULL, *_pdata; char *requestBuffer = NULL; char *responseBuffer = NULL; sdp_hdr_t *pduRequestHeader; sdp_hdr_t *pduResponseHeader; uint8_t dataType; slist_t *svcRecHandleList = NULL; sdppdu_t concatenatedResponseBuffer; sdp_cs_t *pCState = NULL; int bytesScanned = 0; *maxAttrResponseByteCount = 0; if ((attrReqType != IndividualAttributes) && (attrReqType != RangeOfAttributes)) return SDP_ERR_INVALID_ARG; requestBuffer = (char *)malloc(SDP_REQ_BUF_SIZE); if (!requestBuffer) return -1; responseBuffer = (char *)malloc(SDP_RSP_BUF_SIZE); if (!responseBuffer) { free(requestBuffer); return -1; } memset((char *)&concatenatedResponseBuffer, 0, sizeof(sdppdu_t)); pduRequestHeader = (sdp_hdr_t *)requestBuffer; pduRequestHeader->pduId = SDP_PDU_SEARCH_ATTR_REQ; // generate PDU
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -