📄 request.c
字号:
/* Service Discovery Protocol (SDP) Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>, Stephen Crane <steve.crane@rococosoft.com> Based on original SDP implementation by Nokia Corporation. Copyright (C) 2001,2002 Nokia Corporation. Original author Guruprasad Krishnamurthy <guruprasad.krishnamurthy@nokia.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.*//* SDP request handling code. Fixes: Guruprasad Krishnamurthy Dmitry Kasatkin - Continuation mechanism*//* * $Id: request.c,v 1.40 2003/09/23 16:48:44 jscrane Exp $ */#include <malloc.h>#include "sdp.h"#include "sdp_internal.h"#include "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; long cStateId = -1; 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 != -1) { 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;#ifdef SDP_DEBUG if (seq)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -