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

📄 sdpd-request.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * 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;	if (seq)		debug("Entries in attr seq : %d", sdp_list_len(seq));	else		debug("NULL attribute descriptor");	debug("AttrDataType : %d", dtd);	if (seq == NULL) {		debug("Attribute sequence is NULL");		return 0;	}	if (dtd == SDP_UINT16)		for (; seq; seq = seq->next) {			uint16_t attr = bt_get_unaligned((uint16_t *)seq->data);			sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);			if (a)				sdp_append_to_pdu(buf, a);		}	else if (dtd == SDP_UINT32) {		sdp_buf_t pdu;		sdp_gen_record_pdu(rec, &pdu);		for (; seq; seq = seq->next) {			uint32_t range = bt_get_unaligned((uint32_t *)seq->data);			uint16_t attr;			uint16_t low = (0xffff0000 & range) >> 16;			uint16_t high = 0x0000ffff & range;			sdp_data_t *data;			debug("attr range : 0x%x", range);			debug("Low id : 0x%x", low);			debug("High id : 0x%x", high);			if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {				/* copy it */				memcpy(buf->data, pdu.data, pdu.data_size);				buf->data_size = pdu.data_size;				break;			}			/* (else) sub-range of attributes */			for (attr = low; attr < high; attr++) {				data = sdp_data_get(rec, attr);				if (data)					sdp_append_to_pdu(buf, data);			}			data = sdp_data_get(rec, high);			if (data)				sdp_append_to_pdu(buf, data);		}		free(pdu.data);	} else {		error("Unexpected data type : 0x%x", dtd);		error("Expect uint16_t or uint32_t");		return SDP_INVALID_SYNTAX;	}	return 0;}/* * A request for the attributes of a service record. * First check if the service record (specified by * service record handle) exists, then call the attribute * streaming function */static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf){	sdp_cont_state_t *cstate = NULL;	uint8_t *pResponse = NULL;	short cstate_size = 0;	sdp_list_t *seq = NULL;	uint8_t dtd = 0;	int scanned = 0;	int max_rsp_size;	int status = 0, plen, mlen;	uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);	uint32_t handle = ntohl(bt_get_unaligned((uint32_t *)pdata));	pdata += sizeof(uint32_t);	max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata));	pdata += sizeof(uint16_t);	/* extract the attribute list */	scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),						&seq, &dtd, SDP_TYPE_ANY);	if (scanned == -1) {		status = SDP_INVALID_SYNTAX;		goto done;	}	pdata += scanned;	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);	mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1;	// ensure we don't read past buffer	if (plen < mlen || plen != mlen + *(uint8_t *)pdata) {		status = SDP_INVALID_SYNTAX;		goto done;	}	/*	 * if continuation state exists, attempt	 * to get rsp remainder from cache, else send error	 */	cstate = sdp_cstate_get(pdata);	debug("SvcRecHandle : 0x%x", handle);	debug("max_rsp_size : %d", max_rsp_size);	/* 	 * Calculate Attribute size acording to MTU	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))	 */	max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) - 			sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));	/* pull header for AttributeList byte count */	buf->data += sizeof(uint16_t);	buf->buf_size -= sizeof(uint16_t);	if (cstate) {		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);		debug("Obtained cached rsp : %p", pCache);		if (pCache) {			short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent);			pResponse = pCache->data;			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);			buf->data_size += sent;			cstate->cStateValue.maxBytesSent += sent;			debug("Response size : %d sending now : %d bytes sent so far : %d",				pCache->data_size, sent, cstate->cStateValue.maxBytesSent);			if (cstate->cStateValue.maxBytesSent == pCache->data_size)				cstate_size = sdp_set_cstate_pdu(buf, NULL);			else				cstate_size = sdp_set_cstate_pdu(buf, cstate);		} else {			status = SDP_INVALID_CSTATE;			error("NULL cache buffer and non-NULL continuation state");		}	} else {		sdp_record_t *rec = sdp_record_find(handle);		status = extract_attrs(rec, seq, dtd, buf);		if (buf->data_size > max_rsp_size) {			sdp_cont_state_t newState;			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));			newState.timestamp = sdp_cstate_alloc_buf(buf);			/*			 * Reset the buffer size to the maximum expected and			 * set the sdp_cont_state_t			 */			debug("Creating continuation state of size : %d", buf->data_size);			buf->data_size = max_rsp_size;			newState.cStateValue.maxBytesSent = max_rsp_size;			cstate_size = sdp_set_cstate_pdu(buf, &newState);		} else {			if (buf->data_size == 0)				sdp_append_to_buf(buf, 0, 0);			cstate_size = sdp_set_cstate_pdu(buf, NULL);		}	}	// push header	buf->data -= sizeof(uint16_t);	buf->buf_size += sizeof(uint16_t);done:	if (cstate)		free(cstate);	if (seq)                sdp_list_free(seq, free);	if (status)		return status;	/* set attribute list byte count */	bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);	buf->data_size += sizeof(uint16_t);	return 0;}/* * combined service search and attribute extraction */static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf){	int status = 0, plen, totscanned;	uint8_t *pdata, *pResponse = NULL;	int scanned, max, rsp_count = 0;	sdp_list_t *pattern = NULL, *seq = NULL, *svcList;	sdp_cont_state_t *cstate = NULL;	short cstate_size = 0;	uint8_t dtd = 0;	sdp_buf_t tmpbuf;	tmpbuf.data = NULL;	pdata = req->buf + sizeof(sdp_pdu_hdr_t);	scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),					&pattern, &dtd, SDP_TYPE_UUID);	if (scanned == -1) {        	status = SDP_INVALID_SYNTAX;		goto done;	}	totscanned = scanned;	debug("Bytes scanned: %d", scanned);	pdata += scanned;	max = ntohs(bt_get_unaligned((uint16_t *)pdata));	pdata += sizeof(uint16_t);	debug("Max Attr expected: %d", max);	/* extract the attribute list */	scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),						&seq, &dtd, SDP_TYPE_ANY);	if (scanned == -1) {		status = SDP_INVALID_SYNTAX;		goto done;	}	pdata += scanned;	totscanned += scanned + sizeof(uint16_t) + 1;	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);	if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {		status = SDP_INVALID_SYNTAX;		goto done;	}	/*	 * if continuation state exists attempt	 * to get rsp remainder from cache, else send error	 */	cstate = sdp_cstate_get(pdata);	// continuation information	svcList = sdp_get_record_list();	tmpbuf.data = malloc(USHRT_MAX);	tmpbuf.data_size = 0;	tmpbuf.buf_size = USHRT_MAX;	memset(tmpbuf.data, 0, USHRT_MAX);	/* 	 * Calculate Attribute size acording to MTU	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))	 */	max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));	/* pull header for AttributeList byte count */	buf->data += sizeof(uint16_t);	buf->buf_size -= sizeof(uint16_t);	if (cstate == NULL) {		/* no continuation state -> create new response */		sdp_list_t *p;		for (p = svcList; p; p = p->next) {			sdp_record_t *rec = (sdp_record_t *) p->data;			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&					sdp_check_access(rec->handle, &req->device)) {				rsp_count++;				status = extract_attrs(rec, seq, dtd, &tmpbuf);				debug("Response count : %d", rsp_count);				debug("Local PDU size : %d", tmpbuf.data_size);				if (status) {					debug("Extract attr from record returns err");					break;				}				if (buf->data_size + tmpbuf.data_size < buf->buf_size) {					// to be sure no relocations					sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);					tmpbuf.data_size = 0;					memset(tmpbuf.data, 0, USHRT_MAX);				} else {					error("Relocation needed");					break;				}				debug("Net PDU size : %d", buf->data_size);			}		}		if (buf->data_size > max) {			sdp_cont_state_t newState;			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));			newState.timestamp = sdp_cstate_alloc_buf(buf);			/*			 * Reset the buffer size to the maximum expected and			 * set the sdp_cont_state_t			 */			buf->data_size = max;			newState.cStateValue.maxBytesSent = max;			cstate_size = sdp_set_cstate_pdu(buf, &newState);		} else			cstate_size = sdp_set_cstate_pdu(buf, NULL);	} else {		/* continuation State exists -> get from cache */		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);		if (pCache) {			uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);			pResponse = pCache->data;			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);			buf->data_size += sent;			cstate->cStateValue.maxBytesSent += sent;			if (cstate->cStateValue.maxBytesSent == pCache->data_size)				cstate_size = sdp_set_cstate_pdu(buf, NULL);			else				cstate_size = sdp_set_cstate_pdu(buf, cstate);		} else {			status = SDP_INVALID_CSTATE;			debug("Non-null continuation state, but null cache buffer");		}	}	if (!rsp_count && !cstate) {		// found nothing		buf->data_size = 0;		sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);		sdp_set_cstate_pdu(buf, NULL);	}	// push header	buf->data -= sizeof(uint16_t);	buf->buf_size += sizeof(uint16_t);	if (!status) {		/* set attribute list byte count */		bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);		buf->data_size += sizeof(uint16_t);	}done:	if (cstate)		free(cstate);	if (tmpbuf.data)		free(tmpbuf.data);	if (pattern)		sdp_list_free(pattern, free);	if (seq)                sdp_list_free(seq, free);	return status;}/* * Top level request processor. Calls the appropriate processing * function based on request type. Handles service registration * client requests also. */static void process_request(sdp_req_t *req){	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;	sdp_pdu_hdr_t *rsphdr;	sdp_buf_t rsp;	uint8_t *buf = malloc(USHRT_MAX);	int sent = 0;	int status = SDP_INVALID_SYNTAX;	memset(buf, 0, USHRT_MAX);	rsp.data = buf + sizeof(sdp_pdu_hdr_t);	rsp.data_size = 0;	rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);	rsphdr = (sdp_pdu_hdr_t *)buf;	if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {		status = SDP_INVALID_PDU_SIZE;		goto send_rsp;	}	switch (reqhdr->pdu_id) {	case SDP_SVC_SEARCH_REQ:		debug("Got a svc srch req");		status = service_search_req(req, &rsp);		rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;		break;	case SDP_SVC_ATTR_REQ:		debug("Got a svc attr req");		status = service_attr_req(req, &rsp);		rsphdr->pdu_id = SDP_SVC_ATTR_RSP;		break;	case SDP_SVC_SEARCH_ATTR_REQ:		debug("Got a svc srch attr req");		status = service_search_attr_req(req, &rsp);		rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;		break;	/* Following requests are allowed only for local connections */	case SDP_SVC_REGISTER_REQ:		debug("Service register request");		if (req->local) {			status = service_register_req(req, &rsp);			rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;		}		break;	case SDP_SVC_UPDATE_REQ:		debug("Service update request");		if (req->local) {			status = service_update_req(req, &rsp);			rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;		}		break;	case SDP_SVC_REMOVE_REQ:		debug("Service removal request");		if (req->local) {			status = service_remove_req(req, &rsp);			rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;		}		break;	default:		error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);		status = SDP_INVALID_SYNTAX;		break;	}send_rsp:	if (status) {		rsphdr->pdu_id = SDP_ERROR_RSP;		bt_put_unaligned(htons(status), (uint16_t *)rsp.data);		rsp.data_size = sizeof(uint16_t);	}		debug("Sending rsp. status %d", status);	rsphdr->tid  = reqhdr->tid;	rsphdr->plen = htons(rsp.data_size);	/* point back to the real buffer start and set the real rsp length */	rsp.data_size += sizeof(sdp_pdu_hdr_t);	rsp.data = buf;	/* stream the rsp PDU */	sent = send(req->sock, rsp.data, rsp.data_size, 0);	debug("Bytes Sent : %d", sent);	free(rsp.data);	free(req->buf);}void handle_request(int sk, uint8_t *data, int len){	struct sockaddr_l2 sa;	socklen_t size;	sdp_req_t req;	size = sizeof(sa);	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0)		return;	if (sa.l2_family == AF_BLUETOOTH) { 		struct l2cap_options lo;		memset(&lo, 0, sizeof(lo));		size = sizeof(lo);		getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size);		bacpy(&req.bdaddr, &sa.l2_bdaddr);		req.mtu = lo.omtu;		req.local = 0;		memset(&sa, 0, sizeof(sa));		size = sizeof(sa);		getsockname(sk, (struct sockaddr *) &sa, &size);		bacpy(&req.device, &sa.l2_bdaddr);	} else {		bacpy(&req.device, BDADDR_ANY);		bacpy(&req.bdaddr, BDADDR_LOCAL);		req.mtu = 2048;		req.local = 1;	}	req.sock = sk;	req.buf  = data;	req.len  = len;	process_request(&req);}

⌨️ 快捷键说明

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