Add first draft XML based service record registration

This commit is contained in:
Marcel Holtmann 2006-11-22 06:06:36 +00:00
parent 4195a470a5
commit 214cc18ef9
6 changed files with 845 additions and 26 deletions

View File

@ -25,4 +25,15 @@
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include "logging.h"
#include "sdp-xml.h"
sdp_record_t *sdp_xml_parse_record(const char *data, int size)
{
error("No XML parser available");
return -1;
}

View File

@ -25,9 +25,390 @@
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <expat.h>
#include "logging.h"
#include "sdp-xml.h"
/* Expat specific implementation of the context struct */
struct sdp_xml_data {
char *text; /* Pointer to the current buffer */
int size; /* Size of the current buffer */
sdp_data_t *data; /* The current item being built */
struct sdp_xml_data *next; /* Next item on the stack */
char type; /* 0 = Text or Hexadecimal */
char *name; /* Name, optional in the dtd */
/* TODO: What is it used for? */
};
struct sdp_xml_context {
XML_Parser parser; /* Parser object being used */
sdp_record_t *sdprec; /* SDP Record being built */
struct sdp_xml_data *stack_head; /* Top of the stack of attributes */
int attrId; /* Id of the most recently processed attribute */
};
#define DEFAULT_XML_DATA_SIZE 1024
static struct sdp_xml_data *sdp_xml_data_alloc()
{
struct sdp_xml_data *elem;
elem = malloc(sizeof(struct sdp_xml_data));
/* Null terminate the text */
elem->size = DEFAULT_XML_DATA_SIZE;
elem->text = malloc(DEFAULT_XML_DATA_SIZE);
elem->text[0] = '\0';
elem->next = 0;
elem->data = 0;
elem->type = 0;
elem->name = 0;
return elem;
}
static void sdp_xml_data_free(struct sdp_xml_data *elem)
{
if (elem->data)
sdp_data_free(elem->data);
if (elem->name)
free(elem->name);
free(elem->text);
free(elem);
}
static struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
{
char *newbuf;
newbuf = malloc(elem->size * 2);
if (!newbuf)
return NULL;
memcpy(newbuf, elem->text, elem->size);
elem->size *= 2;
free(elem->text);
elem->text = newbuf;
return elem;
}
static sdp_data_t *sdp_xml_parse_datatype(const char *el,
struct sdp_xml_context *context)
{
const char *data = context->stack_head->text;
if (!strcmp(el, "bool"))
return sdp_xml_parse_int(data, SDP_BOOL);
else if (!strcmp(el, "uint8"))
return sdp_xml_parse_int(data, SDP_UINT8);
else if (!strcmp(el, "uint16"))
return sdp_xml_parse_int(data, SDP_UINT16);
else if (!strcmp(el, "uint32"))
return sdp_xml_parse_int(data, SDP_UINT32);
else if (!strcmp(el, "uint64"))
return sdp_xml_parse_int(data, SDP_UINT64);
else if (!strcmp(el, "uint128"))
return sdp_xml_parse_int(data, SDP_UINT128);
else if (!strcmp(el, "int8"))
return sdp_xml_parse_int(data, SDP_INT8);
else if (!strcmp(el, "int16"))
return sdp_xml_parse_int(data, SDP_INT16);
else if (!strcmp(el, "int32"))
return sdp_xml_parse_int(data, SDP_INT32);
else if (!strcmp(el, "int64"))
return sdp_xml_parse_int(data, SDP_INT64);
else if (!strcmp(el, "int128"))
return sdp_xml_parse_int(data, SDP_INT128);
else if (!strcmp(el, "uuid"))
return sdp_xml_parse_uuid(data);
else if (!strcmp(el, "url"))
return sdp_xml_parse_url(data);
else if (!strcmp(el, "text"))
return sdp_xml_parse_text(data, context->stack_head->type);
else if (!strcmp(el, "nil"))
return sdp_xml_parse_nil(data);
return NULL;
}
static void convert_xml_to_sdp_start(void *data, const char *el, const char **attr)
{
struct sdp_xml_context *context = data;
int i;
if (!strcmp(el, "record"))
return;
if (!strcmp(el, "attribute")) {
/* Get the ID */
for (i = 0; attr[i]; i += 1) {
if (!strcmp(attr[i], "id")) {
context->attrId =
strtol(attr[i + 1], 0, 0);
break;
}
}
return;
}
/* Assume every other tag is an element of some sort */
if (context->stack_head) {
struct sdp_xml_data *newelem = sdp_xml_data_alloc();
newelem->next = context->stack_head;
context->stack_head = newelem;
} else {
context->stack_head = sdp_xml_data_alloc();
context->stack_head->next = 0;
}
if (!strcmp(el, "sequence"))
context->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
else if (!strcmp(el, "alternate"))
context->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
else {
const char *type = el;
/* Parse value, name, encoding */
for (i = 0; attr[i]; i += 2) {
if (!strcmp(attr[i], "value")) {
int curlen =
strlen(context->stack_head->text);
int attrlen = strlen(attr[i + 1]);
/* Ensure we're big enough */
while ((curlen + 1 + attrlen) >
context->stack_head->size) {
sdp_xml_data_expand(context->
stack_head);
}
memcpy(&context->stack_head->text[curlen],
attr[i + 1], attrlen);
context->stack_head->text[curlen +
attrlen] = '\0';
}
if (!strcmp(attr[i], "encoding")) {
if (!strcmp(attr[i + 1], "hex"))
context->stack_head->type = 1;
}
if (!strcmp(attr[i], "name")) {
context->stack_head->name =
strdup(attr[i + 1]);
}
}
context->stack_head->data =
sdp_xml_parse_datatype(type, context);
/* Could not parse an entry */
if (context->stack_head->data == NULL)
XML_StopParser(context->parser, 0);
}
}
static int compute_seq_size(sdp_data_t *data)
{
int unit_size = data->unitSize;
sdp_data_t *seq = data->val.dataseq;
for (; seq; seq = seq->next)
unit_size += seq->unitSize;
return unit_size;
}
static void convert_xml_to_sdp_end(void *data, const char *el)
{
struct sdp_xml_context *context = data;
struct sdp_xml_data *elem;
if (!strcmp(el, "record"))
return;
if (!strcmp(el, "attribute")) {
if (context->stack_head && context->stack_head->data) {
int ret = sdp_attr_add(context->sdprec,
context->attrId,
context->stack_head->data);
if (ret == -1)
debug("Trouble adding attribute\n");
context->stack_head->data = 0;
sdp_xml_data_free(context->stack_head);
context->stack_head = 0;
} else {
debug("No Data for attribute: %d\n",
context->attrId);
}
return;
} else if (!strcmp(el, "sequence")) {
context->stack_head->data->unitSize =
compute_seq_size(context->stack_head->data);
if (context->stack_head->data->unitSize > USHRT_MAX) {
context->stack_head->data->unitSize +=
sizeof(uint32_t);
context->stack_head->data->dtd = SDP_SEQ32;
} else if (context->stack_head->data->unitSize > UCHAR_MAX) {
context->stack_head->data->unitSize +=
sizeof(uint16_t);
context->stack_head->data->dtd = SDP_SEQ16;
} else {
context->stack_head->data->unitSize +=
sizeof(uint8_t);
}
} else if (!strcmp(el, "alternate")) {
context->stack_head->data->unitSize =
compute_seq_size(context->stack_head->data);
if (context->stack_head->data->unitSize > USHRT_MAX) {
context->stack_head->data->unitSize +=
sizeof(uint32_t);
context->stack_head->data->dtd = SDP_ALT32;
} else if (context->stack_head->data->unitSize > UCHAR_MAX) {
context->stack_head->data->unitSize +=
sizeof(uint16_t);
context->stack_head->data->dtd = SDP_ALT16;
} else {
context->stack_head->data->unitSize +=
sizeof(uint8_t);
}
}
/* If we're not inside a seq or alt, then we're inside an attribute
which will be taken care of later
*/
if (context->stack_head->next &&
context->stack_head->data && context->stack_head->next->data) {
switch (context->stack_head->next->data->dtd) {
case SDP_SEQ8:
case SDP_SEQ16:
case SDP_SEQ32:
case SDP_ALT8:
case SDP_ALT16:
case SDP_ALT32:
context->stack_head->next->data->val.
dataseq =
sdp_seq_append(context->
stack_head->
next->data->
val.dataseq,
context->stack_head->data);
context->stack_head->data = 0;
break;
}
elem = context->stack_head;
context->stack_head = context->stack_head->next;
sdp_xml_data_free(elem);
}
}
static struct sdp_xml_context *sdp_xml_init_context()
{
struct sdp_xml_context *context;
context = malloc(sizeof(struct sdp_xml_context));
if (!context)
return NULL;
context->parser = 0;
context->sdprec = 0;
context->stack_head = 0;
context->parser = XML_ParserCreate(NULL);
XML_SetElementHandler(context->parser, convert_xml_to_sdp_start,
convert_xml_to_sdp_end);
XML_SetUserData(context->parser, context);
if (!context->parser)
goto fail;
context->sdprec = sdp_record_alloc();
if (!context->sdprec)
goto fail;
return context;
fail:
if (context->parser)
free(context->parser);
if (context->sdprec)
sdp_record_free(context->sdprec);
if (context)
free(context);
return NULL;
}
static void sdp_xml_free_context(struct sdp_xml_context *context)
{
struct sdp_xml_data *elem;
/* Free the stack */
while (context->stack_head) {
elem = context->stack_head;
context->stack_head = elem->next;
sdp_xml_data_free(elem);
}
XML_ParserFree(context->parser);
free(context);
}
static int sdp_xml_parse_chunk(struct sdp_xml_context *context,
const char *data, int size, int final)
{
if (!XML_Parse(context->parser, data, size, final)) {
error("Parse error at line %d: %s\n",
XML_GetCurrentLineNumber(context->parser),
XML_ErrorString(XML_GetErrorCode(context->parser)));
return -1;
}
return 0;
}
sdp_record_t *sdp_xml_parse_record(const char *data, int size)
{
struct sdp_xml_context *context;
sdp_record_t *record;
context = sdp_xml_init_context();
if (sdp_xml_parse_chunk(context, data, size, 1) < 0) {
sdp_record_free(context->sdprec);
sdp_xml_free_context(context);
return NULL;
}
record = context->sdprec;
sdp_xml_free_context(context);
return record;
}

View File

@ -31,17 +31,20 @@
#include <malloc.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include "logging.h"
#include "sdp-xml.h"
#define STRBUFSIZE 256
#define STRBUFSIZE 1024
#define MAXINDENT 64
static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
void *data, void (*appender) (void *, const char *))
void *data, void (*appender)(void *, const char *))
{
int i, hex;
char buf[STRBUFSIZE];
@ -70,12 +73,14 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, indent);
appender(data, "<nil/>\n");
break;
case SDP_BOOL:
appender(data, indent);
appender(data, "<boolean value=\"");
appender(data, value->val.uint8 ? "true" : "false");
appender(data, "\" />\n");
break;
case SDP_UINT8:
appender(data, indent);
appender(data, "<uint8 value=\"");
@ -83,6 +88,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_UINT16:
appender(data, indent);
appender(data, "<uint16 value=\"");
@ -90,6 +96,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_UINT32:
appender(data, indent);
appender(data, "<uint32 value=\"");
@ -97,6 +104,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_UINT64:
appender(data, indent);
appender(data, "<uint64 value=\"");
@ -104,6 +112,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_UINT128:
appender(data, indent);
appender(data, "<uint128 value=\"");
@ -116,6 +125,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_INT8:
appender(data, indent);
appender(data, "<int8 value=\"");
@ -123,6 +133,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_INT16:
appender(data, indent);
appender(data, "<int16 value=\"");
@ -130,6 +141,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_INT32:
appender(data, indent);
appender(data, "<int32 value=\"");
@ -137,6 +149,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_INT64:
appender(data, indent);
appender(data, "<int64 value=\"");
@ -144,6 +157,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_INT128:
appender(data, indent);
appender(data, "<int128 value=\"");
@ -156,22 +170,23 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, "\" />\n");
break;
case SDP_UUID16:
appender(data, indent);
appender(data, "<uuid value=\"");
snprintf(buf, STRBUFSIZE - 1, "0x%04x",
value->val.uuid.value.uuid16);
snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_UUID32:
appender(data, indent);
appender(data, "<uuid value=\"");
snprintf(buf, STRBUFSIZE - 1, "0x%08x",
value->val.uuid.value.uuid32);
snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_UUID128:
appender(data, indent);
appender(data, "<uuid value=\"");
@ -214,6 +229,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, buf);
appender(data, "\" />\n");
break;
case SDP_TEXT_STR8:
case SDP_TEXT_STR16:
case SDP_TEXT_STR32:
@ -256,7 +272,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
This is safe for Normal strings, but not
hex encoded data */
for (i = 0; i < (value->unitSize-1); i++)
sprintf(&strBuf[i * sizeof (char) * 2],
sprintf(&strBuf[i*sizeof(char)*2],
"%02x",
(unsigned char) value->val.str[i]);
@ -306,6 +322,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
free(strBuf);
break;
}
case SDP_URL_STR8:
case SDP_URL_STR16:
case SDP_URL_STR32:
@ -314,6 +331,7 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, value->val.str);
appender(data, "\" />\n");
break;
case SDP_SEQ8:
case SDP_SEQ16:
case SDP_SEQ32:
@ -321,13 +339,13 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, "<sequence>\n");
convert_raw_data_to_xml(value->val.dataseq,
indent_level + 1, data,
appender);
indent_level + 1, data, appender);
appender(data, indent);
appender(data, "</sequence>\n");
break;
case SDP_ALT8:
case SDP_ALT16:
case SDP_ALT32:
@ -336,25 +354,20 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
appender(data, "<alternate>\n");
convert_raw_data_to_xml(value->val.dataseq,
indent_level + 1, data,
appender);
indent_level + 1, data, appender);
appender(data, indent);
appender(data, "</alternate>\n");
break;
default:
break;
}
convert_raw_data_to_xml(value->next, indent_level, data,
appender);
convert_raw_data_to_xml(value->next, indent_level, data, appender);
}
struct conversion_data
{
struct conversion_data {
void *data;
void (*appender) (void *data, const char *);
void (*appender)(void *data, const char *);
};
static void convert_raw_attr_to_xml_func(void *val, void *data)
@ -369,8 +382,7 @@ static void convert_raw_attr_to_xml_func(void *val, void *data)
cd->appender(cd->data, buf);
if (data)
convert_raw_data_to_xml(value, 2, cd->data,
cd->appender);
convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
else
cd->appender(cd->data, "\t\tNULL\n");
@ -378,13 +390,13 @@ static void convert_raw_attr_to_xml_func(void *val, void *data)
}
/*
Will convert the sdp record to XML. The appender and data can be used
to control where to output the record (e.g. file or a data buffer). The
appender will be called repeatedly with data and the character buffer
(containing parts of the generated XML) to append.
*/
* Will convert the sdp record to XML. The appender and data can be used
* to control where to output the record (e.g. file or a data buffer). The
* appender will be called repeatedly with data and the character buffer
* (containing parts of the generated XML) to append.
*/
void convert_sdp_record_to_xml(sdp_record_t *rec,
void *data, void (*appender) (void *, const char *))
void *data, void (*appender)(void *, const char *))
{
struct conversion_data cd;
@ -399,3 +411,293 @@ void convert_sdp_record_to_xml(sdp_record_t *rec,
appender(data, "</record>\n");
}
}
static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
{
uint128_t val;
int i;
int j;
char buf[3];
memset(&val, 0, sizeof(val));
buf[2] = '\0';
for (j = 0, i = 0; i < strlen(data);) {
if (data[i] == '-') {
i++;
continue;
}
buf[0] = data[i];
buf[1] = data[i + 1];
val.data[j++] = strtoul(buf, 0, 16);
i += 2;
}
return sdp_data_alloc(SDP_UUID128, &val);
}
sdp_data_t *sdp_xml_parse_uuid(const char *data)
{
int len;
char *endptr;
uint32_t val;
uint16_t val2 = val;
len = strlen(data);
if (len == 36)
return sdp_xml_parse_uuid128(data);
val = strtoll(data, &endptr, 16);
/* Couldn't parse */
if (*endptr != '\0')
return NULL;
if (val > USHRT_MAX)
return sdp_data_alloc(SDP_UUID32, &val);
return sdp_data_alloc(SDP_UUID16, &val2);
/* Should never get here */
return NULL;
}
sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
{
char *endptr;
sdp_data_t *ret = NULL;
switch (dtd) {
case SDP_BOOL:
{
uint8_t val = 0;
if (!strcmp("true", data)) {
val = 1;
}
else if (!strcmp("false", data)) {
val = 0;
}
else {
return NULL;
}
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_INT8:
{
int8_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_UINT8:
{
uint8_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_INT16:
{
int16_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_UINT16:
{
uint16_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_INT32:
{
int32_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_UINT32:
{
uint32_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_INT64:
{
int64_t val = strtoull(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_UINT64:
{
uint64_t val = strtoull(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
}
case SDP_INT128:
case SDP_UINT128:
{
uint128_t val;
int i = 0;
char buf[3];
buf[2] = '\0';
for (; i < 32; i += 2) {
buf[0] = data[i];
buf[1] = data[i + 1];
val.data[i] = strtoul(buf, 0, 16);
}
ret = sdp_data_alloc(dtd, &val);
break;
}
};
return ret;
}
static sdp_data_t *sdp_xml_parse_url_with_size(const char *data, uint8_t dtd)
{
return sdp_data_alloc(dtd, data);
}
sdp_data_t *sdp_xml_parse_url(const char *data)
{
uint8_t dtd = SDP_URL_STR8;
if (strlen(data) > UCHAR_MAX)
dtd = SDP_URL_STR16;
return sdp_xml_parse_url_with_size(data, dtd);
}
static char *sdp_xml_parse_text_decode(const char *data, char encoding, uint32_t *length)
{
int len = strlen(data);
char *text;
if (encoding == SDP_XML_ENCODING_NORMAL) {
text = strdup(data);
*length = len;
} else {
char buf[3], *decoded;
int i;
decoded = malloc((len >> 1) + 1);
/* Ensure the string is a power of 2 */
len = (len >> 1) << 1;
buf[2] = '\0';
for (i = 0; i < len; i += 2) {
buf[0] = data[i];
buf[1] = data[i + 1];
decoded[i >> 1] = strtoul(buf, 0, 16);
}
decoded[len >> 1] = '\0';
text = decoded;
*length = len >> 1;
}
return text;
}
#if 0
static sdp_data_t *sdp_xml_parse_text_with_size(const char *data, char encoding, uint8_t dtd)
{
char *text;
uint32_t length;
sdp_data_t *ret;
text = sdp_xml_parse_text_decode(data, encoding, &length);
ret = sdp_data_alloc_with_length(dtd, text, length);
debug("Unit size %d length %d: -->%s<--\n", ret->unitSize, length, text);
return ret;
}
#endif
sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
{
uint8_t dtd = SDP_TEXT_STR8;
char *text;
uint32_t length;
sdp_data_t *ret;
text = sdp_xml_parse_text_decode(data, encoding, &length);
if (length > UCHAR_MAX)
dtd = SDP_TEXT_STR16;
ret = sdp_data_alloc_with_length(dtd, text, length);
debug("Unit size %d length %d: -->%s<--\n", ret->unitSize, length, text);
return ret;
}
sdp_data_t *sdp_xml_parse_nil(const char *data)
{
return sdp_data_alloc(SDP_DATA_NIL, 0);
}

View File

@ -27,7 +27,18 @@
#include <bluetooth/sdp.h>
#define SDP_XML_ENCODING_NORMAL 0
#define SDP_XML_ENCODING_HEX 1
void convert_sdp_record_to_xml(sdp_record_t *rec,
void *user_data, void (*append_func) (void *, const char *));
sdp_data_t *sdp_xml_parse_nil(const char *data);
sdp_data_t *sdp_xml_parse_text(const char *data, char encoding);
sdp_data_t *sdp_xml_parse_url(const char *data);
sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd);
sdp_data_t *sdp_xml_parse_uuid(const char *data);
sdp_record_t *sdp_xml_parse_record(const char *data, int size);
#endif /* __SDP_XML_H */

View File

@ -191,6 +191,17 @@ Methods uint32 InterfaceVersion()
registered, otherwise the record will be available
when the service agent Start method is called.
uint32 AddServiceRecordAsXML(string path, string record)
Add a new service record to the service agent
and returns the assigned handle.
The path parameter is the object path of the
service agent. The record parameter is the XML
representation of a service record. If the service
agent is running the service record will be automatically
registered, otherwise the record will be available
when the service agent Start method is called.
void RemoveServiceRecord(string path, uint32 handle)

View File

@ -28,12 +28,15 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <dbus/dbus.h>
@ -45,6 +48,7 @@
#include "dbus-security.h"
#include "dbus-service.h"
#include "dbus-manager.h"
#include "sdp-xml.h"
static int default_adapter_id = -1;
static int autostart = 1;
@ -473,6 +477,104 @@ fail:
return error_failed(conn, msg, err);
}
static DBusHandlerResult add_service_record_xml(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct service_agent *agent;
DBusMessage *reply;
struct binary_record *rec;
sdp_record_t *sdp_rec;
const char *path;
const char *record;
int err;
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_STRING, &path,
DBUS_TYPE_STRING, &record,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
if (!dbus_connection_get_object_path_data(conn, path,
(void *) &agent)) {
/* If failed the path is invalid! */
return error_invalid_arguments(conn, msg);
}
if (!agent || strcmp(dbus_message_get_sender(msg), agent->id))
return error_not_authorized(conn, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
sdp_rec = sdp_xml_parse_record(record, strlen(record));
if (!sdp_rec) {
error("Parsing of XML service record failed");
dbus_message_unref(reply);
return error_invalid_arguments(conn, msg);
}
/* TODO: Is this correct? We remove the record handle attribute
(if it exists) so SDP server assigns a new one */
sdp_attr_remove(sdp_rec, 0x0);
rec = binary_record_new();
if (!rec) {
sdp_record_free(sdp_rec);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
rec->buf = malloc(sizeof(sdp_buf_t));
if (!rec->buf) {
sdp_record_free(sdp_rec);
binary_record_free(rec);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
/* Generate binary record */
if (sdp_gen_record_pdu(sdp_rec, rec->buf) != 0) {
sdp_record_free(sdp_rec);
binary_record_free(rec);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
sdp_record_free(sdp_rec);
/* Assign a new handle */
rec->ext_handle = next_handle++;
if (agent->running) {
uint32_t handle = 0;
if (register_sdp_record(rec->buf->data, rec->buf->data_size, &handle) < 0) {
err = errno;
error("Service record registration failed: %s (%d)",
strerror(err), err);
goto fail;
}
rec->handle = handle;
}
agent->records = slist_append(agent->records, rec);
dbus_message_append_args(reply,
DBUS_TYPE_UINT32, &rec->ext_handle,
DBUS_TYPE_INVALID);
return send_message_and_unref(conn, reply);
fail:
binary_record_free(rec);
dbus_message_unref(reply);
return error_failed(conn, msg, err);
}
static DBusHandlerResult remove_service_record(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@ -532,6 +634,7 @@ static struct service_data methods[] = {
{ "RegisterService", register_service },
{ "UnregisterService", unregister_service },
{ "AddServiceRecord", add_service_record },
{ "AddServiceRecordAsXML", add_service_record_xml },
{ "RemoveServiceRecord", remove_service_record },
{ NULL, NULL }
};