📄 sdp.c
字号:
}#endifsdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId){ if (rec->attrlist) { sdp_data_t sdpTemplate; sdp_list_t *p; sdpTemplate.attrId = attrId; p = sdp_list_find(rec->attrlist, &sdpTemplate, sdp_attrid_comp_func); if (p) return (sdp_data_t *)p->data; } return 0;}/* * Extract the sequence type and its length, and return offset into buf * or 0 on failure. */int sdp_extract_seqtype(const char *buf, uint8_t *dtdp, int *size){ uint8_t dtd = *(uint8_t *)buf; int scanned = sizeof(uint8_t); buf += sizeof(uint8_t); *dtdp = dtd; switch (dtd) { case SDP_SEQ8: case SDP_ALT8: *size = *(uint8_t *)buf; scanned += sizeof(uint8_t); break; case SDP_SEQ16: case SDP_ALT16: *size = ntohs(sdp_get_unaligned((uint16_t *)buf)); scanned += sizeof(uint16_t); break; case SDP_SEQ32: case SDP_ALT32: *size = ntohl(sdp_get_unaligned((uint32_t *)buf)); scanned += sizeof(uint32_t); break; default: SDPERR("Unknown sequence type, aborting\n"); return 0; } return scanned;}int sdp_send_req(sdp_session_t *session, char *buf, int size){ int sent = 0; while (sent < size) { int n = send(session->sock, buf + sent, size - sent, 0); if (n < 0) return -1; sent += n; } return 0;}int sdp_read_rsp(sdp_session_t *session, char *buf, int size){ fd_set readFds; struct timeval timeout = { SDP_RESPONSE_TIMEOUT, 0 }; FD_SET(session->sock, &readFds); SDPDBG("Waiting for response\n"); if (0 == select(session->sock + 1, &readFds, NULL, NULL, &timeout)) { SDPERR("Client timed out\n"); errno = ETIMEDOUT; return -1; } return recv(session->sock, buf, size, 0);}/* * generic send request, wait for response method. */int sdp_send_req_w4_rsp(sdp_session_t *session, char *reqbuf, char *rspbuf, int reqsize, int *rspsize){ int n; sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)reqbuf; sdp_pdu_hdr_t *rsphdr = (sdp_pdu_hdr_t *)rspbuf; SDPDBG(""); if (0 > sdp_send_req(session, reqbuf, reqsize)) { SDPERR("Error sending data:%s", strerror(errno)); return -1; } n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE); if (0 > n) return -1; SDPDBG("Read : %d\n", n); if (n == 0 || reqhdr->tid != rsphdr->tid) { errno = EPROTO; return -1; } *rspsize = n; return 0;}/* * singly-linked lists (after openobex implementation) */sdp_list_t *sdp_list_append(sdp_list_t *p, void *d){ sdp_list_t *q, *n = (sdp_list_t *)malloc(sizeof(sdp_list_t)); if (!n) return 0; n->data = d; n->next = 0; if (!p) return n; for (q = p; q->next; q = q->next); q->next = n; return p;}sdp_list_t *sdp_list_remove(sdp_list_t *list, void *d){ sdp_list_t *p, *q; for (q = 0, p = list; p; q = p, p = p->next) if (p->data == d) { if (q) q->next = p->next; else list = p->next; free(p); break; } return list;}sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *d, sdp_comp_func_t f){ sdp_list_t *q, *p, *n; n = (sdp_list_t *)malloc(sizeof(sdp_list_t)); if (!n) return 0; n->data = d; for (q = 0, p = list; p; q = p, p = p->next) if (f(p->data, d) >= 0) break; // insert between q and p; if !q insert at head if (q) q->next = n; else list = n; n->next = p; return list;}/* * Every element of the list points to things which need * to be free()'d. This method frees the list's contents */void sdp_list_free(sdp_list_t *list, sdp_free_func_t f){ sdp_list_t *next; while (list) { next = list->next; if (f) f(list->data); free(list); list = next; }}static inline int __find_port(sdp_data_t *seq, int proto){ if (!seq || !seq->next) return 0; if (SDP_IS_UUID(seq->dtd) && sdp_uuid_to_proto(&seq->val.uuid) == proto) { seq = seq->next; switch (seq->dtd) { case SDP_UINT8: return seq->val.uint8; case SDP_UINT16: return seq->val.uint16; } } return 0;}int sdp_get_proto_port(const sdp_list_t *list, int proto){ if (proto != L2CAP_UUID && proto != RFCOMM_UUID) { errno = EINVAL; return -1; } for (; list; list = list->next) { sdp_list_t *p; for (p = list->data; p; p = p->next) { sdp_data_t *seq = (sdp_data_t *) p->data; int port = __find_port(seq, proto); if (port) return port; } } return 0;}sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto){ for (; list; list = list->next) { sdp_list_t *p; for (p = list->data; p; p = p->next) { sdp_data_t *seq = (sdp_data_t *) p->data; if (SDP_IS_UUID(seq->dtd) && sdp_uuid_to_proto(&seq->val.uuid) == proto) return seq->next; } } return NULL;}int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **pap){ sdp_data_t *pdlist, *curr; sdp_list_t *ap = 0; pdlist = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST); if (pdlist == NULL) { errno = ENODATA; return -1; } SDPDBG("AP type : 0%x\n", pdlist->dtd); for (; pdlist; pdlist = pdlist->next) { sdp_list_t *pds = 0; for (curr = pdlist->val.dataseq; curr; curr = curr->next) pds = sdp_list_append(pds, curr->val.dataseq); ap = sdp_list_append(ap, pds); } *pap = ap; return 0;}int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **pap){ sdp_data_t *pdlist, *curr; sdp_list_t *ap = 0; pdlist = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST); if (pdlist == NULL) { errno = ENODATA; return -1; } SDPDBG("AP type : 0%x\n", pdlist->dtd); pdlist = pdlist->val.dataseq; for (; pdlist; pdlist = pdlist->next) { sdp_list_t *pds = 0; for (curr = pdlist->val.dataseq; curr; curr = curr->next) pds = sdp_list_append(pds, curr->val.dataseq); ap = sdp_list_append(ap, pds); } *pap = ap; return 0;}int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp){ sdp_data_t *sdpdata = sdp_data_get(rec, attr); *seqp = NULL; if (sdpdata && sdpdata->dtd >= SDP_SEQ8 && sdpdata->dtd <= SDP_SEQ32) { sdp_data_t *d; for (d = sdpdata->val.dataseq; d; d = d->next) { uuid_t *u = (uuid_t *)malloc(sizeof(uuid_t)); memset((char *)u, 0, sizeof(uuid_t)); if (d->dtd >= SDP_UUID16 && d->dtd <= SDP_UUID128) { *u = d->val.uuid; *seqp = sdp_list_append(*seqp, u); } else goto fail; } return 0; }fail: sdp_list_free(*seqp, free); errno = EINVAL; return -1;}int sdp_set_uuidseq_attr(sdp_record_t *rec, uint16_t aid, sdp_list_t *seq){ int status = 0, i, len; void **dtds, **values; uint8_t uuid16 = SDP_UUID16; uint8_t uuid32 = SDP_UUID32; uint8_t uuid128 = SDP_UUID128; sdp_list_t *p; len = sdp_list_len(seq); if (!seq || len == 0) return -1; dtds = (void **)malloc(len * sizeof(void *)); values = (void **)malloc(len * sizeof(void *)); for (p = seq, i = 0; i < len; i++, p = p->next) { uuid_t *uuid = (uuid_t *)p->data; if (uuid) switch (uuid->type) { case SDP_UUID16: dtds[i] = &uuid16; values[i] = &uuid->value.uuid16; break; case SDP_UUID32: dtds[i] = &uuid32; values[i] = &uuid->value.uuid32; break; case SDP_UUID128: dtds[i] = &uuid128; values[i] = &uuid->value.uuid128; break; default: status = -1; break; } else { status = -1; break; } } if (status == 0) { sdp_data_t *data = sdp_seq_alloc(dtds, values, len); sdp_attr_replace(rec, aid, data); sdp_pattern_add_uuidseq(rec, seq); } free(dtds); free(values); return status;}int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq){ sdp_lang_attr_t *lang; sdp_data_t *sdpdata, *curr_data; *langSeq = NULL; sdpdata = sdp_data_get(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST); if (sdpdata == NULL) { errno = ENODATA; return -1; } curr_data = sdpdata->val.dataseq; while (curr_data) { sdp_data_t *pCode = curr_data; sdp_data_t *pEncoding = pCode->next; sdp_data_t *pOffset = pEncoding->next; if (pCode && pEncoding && pOffset) { lang = (sdp_lang_attr_t *)malloc(sizeof(sdp_lang_attr_t)); lang->code_ISO639 = pCode->val.uint16; lang->encoding = pEncoding->val.uint16; lang->base_offset = pOffset->val.uint16; SDPDBG("code_ISO639 : 0x%02x\n", lang->code_ISO639); SDPDBG("encoding : 0x%02x\n", lang->encoding); SDPDBG("base_offfset : 0x%02x\n", lang->base_offset); *langSeq = sdp_list_append(*langSeq, lang); } curr_data = pOffset->next; } return 0;}int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq){ sdp_profile_desc_t *profDesc; sdp_data_t *sdpdata, *seq; *profDescSeq = NULL; sdpdata = sdp_data_get(rec, SDP_ATTR_PFILE_DESC_LIST); if (!sdpdata || !sdpdata->val.dataseq) { errno = ENODATA; return -1; } for (seq = sdpdata->val.dataseq; seq && seq->val.dataseq; seq = seq->next) { sdp_data_t *uuid = seq->val.dataseq; sdp_data_t *pVnum = seq->val.dataseq->next; if (uuid && pVnum) { profDesc = (sdp_profile_desc_t *)malloc(sizeof(sdp_profile_desc_t)); profDesc->uuid = uuid->val.uuid; profDesc->version = pVnum->val.uint16;#ifdef SDP_DEBUG sdp_uuid_print(&profDesc->uuid); SDPDBG("Vnum : 0x%04x\n", profDesc->version);#endif *profDescSeq = sdp_list_append(*profDescSeq, profDesc); } } return 0;}int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **u16){ sdp_data_t *d, *curr; *u16 = NULL; d = sdp_data_get(rec, SDP_ATTR_VERSION_NUM_LIST); if (d == NULL) { errno = ENODATA; return -1; } for (curr = d->val.dataseq; curr; curr = curr->next) *u16 = sdp_list_append(*u16, &curr->val.uint16); return 0;}/* flexible extraction of basic attributes - Jean II *//* How do we expect caller to extract predefined data sequences? */int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attrid, int *value){ sdp_data_t *sdpdata = sdp_data_get(rec, attrid); if (sdpdata) /* Verify that it is what the caller expects */ if (sdpdata->dtd == SDP_BOOL || sdpdata->dtd == SDP_UINT8 || sdpdata->dtd == SDP_UINT16 || sdpdata->dtd == SDP_UINT32 || sdpdata->dtd == SDP_INT8 || sdpdata->dtd == SDP_INT16 || sdpdata->dtd == SDP_INT32) { *value = sdpdata->val.uint32; return 0; } errno = EINVAL; return -1;}int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attrid, char *value, int valuelen){ sdp_data_t *sdpdata = sdp_data_get(rec, attrid); if (sdpdata) /* Verify that it is what the caller expects */ if (sdpdata->dtd == SDP_TEXT_STR8 || sdpdata->dtd == SDP_TEXT_STR16 || sdpdata->dtd == SDP_TEXT_STR32) if (strlen(sdpdata->val.str) < valuelen) { strcpy(value, sdpdata->val.str); return 0; } errno = EINVAL; return -1;}#define get_basic_attr(attrID, pAttrValue, fieldName) \ sdp_data_t *data = sdp_data_get(rec, attrID); \ if (data) { \ *pAttrValue = data->val.fieldName; \ return 0; \ } \ errno = EINVAL; \ return -1;int sdp_get_service_id(const sdp_record_t *rec, uuid_t *uuid){ get_basic_attr(SDP_ATTR_SERVICE_ID, uuid, uuid);}int sdp_get_group_id(const sdp_record_t *rec, uuid_t *uuid){ get_basic_attr(SDP_ATTR_GROUP_ID, uuid, uuid);}int sdp_get_record_state(const sdp_record_t *rec, uint32_t *svcRecState){ get_basic_attr(SDP_ATTR_RECORD_STATE, svcRecState, uint32);}int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail){ get_basic_attr(SDP_ATTR_SERVICE_AVAILABILITY, svcAvail, uint8);}int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo){ get_basic_attr(SDP_ATTR_SVCINFO_TTL, svcTTLInfo, uint32);}int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState){ get_basic_attr(SDP_ATTR_SVCDB_STATE, svcDBState, uint32);}/* * NOTE that none of the setXXX() functions below will * actually update the SDP server, unless the * {register, update}sdp_record_t() function is invoked. */int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *value){ sdp_data_t *d = sdp_data_alloc(dtd, value); if (d) { sdp_attr_replace(rec, attr, d); return 0; } return -1;}/* * Set the information attributes of the service * pointed to by rec. The attributes are * service name, description and provider name */void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc){ if (name) sdp_attr_add_new(rec, SDP_ATTR_SVCNAME_PRIMARY, SDP_TEXT_STR8, (void *)name); if (prov) sdp_attr_add_new(rec, SDP_ATTR_PROVNAME_PRIMARY, SDP_TEXT_STR8, (void *)prov); if (desc) sdp_attr_add_new(rec, SDP_ATTR_SVCDESC_PRIMARY, SDP_TEXT_STR8, (void *)desc);}static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto){ sdp_data_t *seq = NULL; void *dtds[10], *values[10];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -