⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 request.c

📁 Bluezan implementation of the Bluetooth&#8482 wireless standards specifications for Linux. The code
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  BlueZ - Bluetooth protocol stack for Linux * *  Copyright (C) 2001-2002  Nokia Corporation *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com> *  Copyright (C) 2002-2004  Marcel Holtmann <marcel@holtmann.org> *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com> * * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 as *  published by the Free Software Foundation; * *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. *  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY *  CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * *  ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,  *  COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS  *  SOFTWARE IS DISCLAIMED. * * *  $Id: request.c,v 1.6 2005/03/09 17:27:18 holtmann Exp $ */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <malloc.h>#include <syslog.h>#include <netinet/in.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include "sdpd.h"#define MIN(x, y) ((x) < (y))? (x): (y)/* Additional values for checking datatype (not in spec) */#define SDP_TYPE_UUID	0xfe#define SDP_TYPE_ANY	0xff/* * Generic data element sequence extractor. Builds * a list whose elements are those found in the  * sequence. The data type of elements found in the * sequence is returned in the reference pDataType */static int extract_des(char *buf, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType){	uint8_t seqType;	int data_size = 0;	int scanned = sdp_extract_seqtype(buf, &seqType, &data_size);	short numberOfElements = 0;	int seqlen = 0;	sdp_list_t *pSeq = NULL;	uint8_t dataType;	int status = 0;	const char *p;	SDPDBG("Seq type : %d\n", seqType);	if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) {		SDPERR("Unknown seq type \n");		return -1;	}	p = buf + scanned;	SDPDBG("Data size : %d\n", data_size);	for (;;) {		char *pElem = NULL;		int localSeqLength = 0;		dataType = *(uint8_t *)p;		SDPDBG("Data type: 0x%02x\n", dataType);		if (expectedType == SDP_TYPE_UUID) {			if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) {				SDPDBG("->Unexpected Data type (expected UUID_ANY)\n");				return -1;			}		} else if (expectedType != SDP_TYPE_ANY && dataType != expectedType) {			SDPDBG("->Unexpected Data type (expected 0x%02x)\n", expectedType);			return -1;		}		switch (dataType) {		case SDP_UINT16:			p += sizeof(uint8_t);			seqlen += sizeof(uint8_t);			pElem = (char *)malloc(sizeof(uint16_t));			sdp_put_unaligned(ntohs(sdp_get_unaligned((uint16_t *)p)), (uint16_t *)pElem);			p += sizeof(uint16_t);			seqlen += sizeof(uint16_t);			break;		case SDP_UINT32:			p += sizeof(uint8_t);			seqlen += sizeof(uint8_t);			pElem = (char *)malloc(sizeof(uint32_t));			sdp_put_unaligned(ntohl(sdp_get_unaligned((uint32_t *)p)), (uint32_t *)pElem);			p += sizeof(uint32_t);			seqlen += sizeof(uint32_t);			break;		case SDP_UUID16:		case SDP_UUID32:		case SDP_UUID128:			pElem = (char *)malloc(sizeof(uuid_t));			status = sdp_uuid_extract(p, (uuid_t *)pElem, &localSeqLength);			if (status == 0) {				seqlen += localSeqLength;				p += localSeqLength;			}			break;		}		if (status == 0) {			pSeq = sdp_list_append(pSeq, pElem);			numberOfElements++;			SDPDBG("No of elements : %d\n", numberOfElements);			if (seqlen == data_size)				break;			else if (seqlen > data_size)				return -1;		} else			free(pElem);	}	*svcReqSeq = pSeq;	scanned += seqlen;	*pDataType = dataType;	return scanned;}static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate){	char *pdata = buf->data + buf->data_size;	int length = 0;	if (cstate) {		SDPDBG("Non null sdp_cstate_t id : 0x%lx\n", cstate->timestamp);		*(uint8_t *)pdata = sizeof(sdp_cont_state_t);		pdata += sizeof(uint8_t);		length += sizeof(uint8_t);		memcpy(pdata, cstate, sizeof(sdp_cont_state_t));		length += sizeof(sdp_cont_state_t);	} else {		// set "null" continuation state		*(uint8_t *)pdata = 0;		pdata += sizeof(uint8_t);		length += sizeof(uint8_t);	}	buf->data_size += length;	return length;}static sdp_cont_state_t *sdp_cstate_get(char *buffer){	char *pdata = buffer;	uint8_t cStateSize = *(uint8_t *)pdata;	/*	 * Check if continuation state exists, if yes attempt	 * to get response remainder from cache, else send error	 */	SDPDBG("Continuation State size : %d\n", cStateSize);	pdata += sizeof(uint8_t);	if (cStateSize != 0) {		sdp_cont_state_t *cstate = (sdp_cont_state_t *)pdata;		SDPDBG("Cstate TS : 0x%lx\n", cstate->timestamp);		SDPDBG("Bytes sent : %d\n", cstate->cStateValue.maxBytesSent);		return cstate;	}	return NULL;}/* * The matching process is defined as "each and every UUID * specified in the "search pattern" must be present in the * "target pattern". Here "search pattern" is the set of UUIDs * specified by the service discovery client and "target pattern" * is the set of UUIDs present in a service record.  *  * Return 1 if each and every UUID in the search * pattern exists in the target pattern, 0 if the * match succeeds and -1 on error. */static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern){	/*	 * The target is a sorted list, so we need not look	 * at all elements to confirm existence of an element	 * from the search pattern	 */	int patlen = sdp_list_len(pattern);	SDPDBG("");	if (patlen < sdp_list_len(search))		return -1;	for (; search; search = search->next) {		uuid_t *uuid128;		void *data = search->data;		sdp_list_t *list;		if (data == NULL)			return -1;		// create 128-bit form of the search UUID		uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);		list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);		free(uuid128);		if (!list)			return 0;	}	return 1;}/* * Service search request PDU. This method extracts the search pattern * (a sequence of UUIDs) and calls the matching function * to find matching services */static int service_search_req(sdp_req_t *req, sdp_buf_t *buf){	int status = 0, i, plen, mlen;	sdp_list_t *pattern = NULL;	int expected, actual;	uint8_t dtd;	sdp_cont_state_t *cstate = NULL;	char *pCacheBuffer = NULL;	int handleSize = 0;	uint32_t cStateId = 0;	short rsp_count = 0;	short *pTotalRecordCount, *pCurrentRecordCount;	int mtu;	char *pdata = req->buf + sizeof(sdp_pdu_hdr_t);	int scanned = extract_des(pdata, &pattern, &dtd, SDP_TYPE_UUID);	SDPDBG("");	if (scanned == -1) {		status = SDP_INVALID_SYNTAX;		goto done;	}	pdata += scanned;	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);	mlen = scanned + sizeof(uint16_t) + 1;	// ensure we don't read past buffer	if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) {		status = SDP_INVALID_SYNTAX;		goto done;	}	expected = ntohs(sdp_get_unaligned((uint16_t *)pdata));		SDPDBG("Expected count: %d\n", expected);	SDPDBG("Bytes scanned : %d\n", scanned);	pdata += sizeof(uint16_t);	/*	 * Check if continuation state exists, if yes attempt	 * to get rsp remainder from cache, else send error	 */	cstate = sdp_cstate_get(pdata);	mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE;	actual = MIN(expected, mtu >> 2);	/* make space in the rsp buffer for total and current record counts */	pdata = buf->data;	/* total service record count = 0 */	pTotalRecordCount = (short *)pdata;	sdp_put_unaligned(0, (uint16_t *)pdata);	pdata += sizeof(uint16_t);	buf->data_size += sizeof(uint16_t);	/* current service record count = 0 */	pCurrentRecordCount = (short *)pdata;	sdp_put_unaligned(0, (uint16_t *)pdata);	pdata += sizeof(uint16_t);	buf->data_size += sizeof(uint16_t);	if (cstate == NULL) {		/* for every record in the DB, do a pattern search */		sdp_list_t *list = sdp_get_record_list();		handleSize = 0;		for (; list && rsp_count < expected; list = list->next) {			sdp_record_t *rec = (sdp_record_t *)list->data;			SDPDBG("Checking svcRec : 0x%x\n", rec->handle);							if (sdp_match_uuid(pattern, rec->pattern) > 0) {				rsp_count++;				sdp_put_unaligned(htonl(rec->handle), (uint32_t *)pdata);				pdata += sizeof(uint32_t);				handleSize += sizeof(uint32_t);			}		}				SDPDBG("Match count: %d\n", rsp_count);		buf->data_size += handleSize;		sdp_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);		sdp_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount);		if (rsp_count > actual) {			/* cache the rsp and generate a continuation state */			cStateId = sdp_cstate_alloc_buf(buf);			/*			 * subtract handleSize since we now send only			 * a subset of handles			 */			buf->data_size -= handleSize;		} else {			/* NULL continuation state */			sdp_set_cstate_pdu(buf, NULL);		}	}	/* under both the conditions below, the rsp buffer is not built yet */	if (cstate || cStateId > 0) {		short lastIndex = 0;		if (cstate) {			/*			 * Get the previous sdp_cont_state_t and obtain			 * the cached rsp			 */			sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);			if (pCache) {				pCacheBuffer = pCache->data;				/* get the rsp_count from the cached buffer */				rsp_count = ntohs(sdp_get_unaligned((uint16_t *)pCacheBuffer));				/* get index of the last sdp_record_t sent */				lastIndex = cstate->cStateValue.lastIndexSent;			} else {				status = SDP_INVALID_CSTATE;				goto done;			}		} else {			pCacheBuffer = buf->data;			lastIndex = 0;		}		/*		 * Set the local buffer pointer to after the		 * current record count and increment the cached		 * buffer pointer to beyond the counters		 */		pdata = (char *)pCurrentRecordCount + sizeof(uint16_t);		/* increment beyond the totalCount and the currentCount */		pCacheBuffer += 2 * sizeof(uint16_t);		if (cstate) {			handleSize = 0;			for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) {				sdp_put_unaligned(sdp_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata);				pdata += sizeof(uint32_t);				handleSize += sizeof(uint32_t);			}		} else {			handleSize = actual << 2;			i = actual;		}		buf->data_size += handleSize;		sdp_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);		sdp_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount);		if (i == rsp_count) {			/* set "null" continuationState */			sdp_set_cstate_pdu(buf, NULL);		} else {			/*			 * there's more: set lastIndexSent to			 * the new value and move on			 */			sdp_cont_state_t newState;			SDPDBG("Setting non-NULL sdp_cstate_t\n");			if (cstate)				memcpy((char *)&newState, cstate, sizeof(sdp_cont_state_t));			else {				memset((char *)&newState, 0, sizeof(sdp_cont_state_t));				newState.timestamp = cStateId;			}			newState.cStateValue.lastIndexSent = i;			sdp_set_cstate_pdu(buf, &newState);		}	}done:		if (pattern)		sdp_list_free(pattern, free);	return status;}/* * 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 */static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, uint8_t dtd, sdp_buf_t *buf){	if (!rec)		return SDP_INVALID_RECORD_HANDLE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -