summaryrefslogtreecommitdiffstats
path: root/hcid
diff options
context:
space:
mode:
authorClaudio Takahasi <claudio.takahasi@openbossa.org>2006-08-01 18:14:36 +0000
committerClaudio Takahasi <claudio.takahasi@openbossa.org>2006-08-01 18:14:36 +0000
commit7469e3053987868c478ceb62d13364a23c57cc17 (patch)
treefde2ff5f484f9fdcbd452e8013792b6da0fe079d /hcid
parent670e5ef72176dafc1bf2669d4c5c30e0db26dd71 (diff)
support for async query
Diffstat (limited to 'hcid')
-rw-r--r--hcid/dbus-sdp.c1125
1 files changed, 588 insertions, 537 deletions
diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c
index 2cfd687c..fe3ad04a 100644
--- a/hcid/dbus-sdp.c
+++ b/hcid/dbus-sdp.c
@@ -50,18 +50,17 @@
#include "hcid.h"
#include "textfile.h"
-#define SDP_UUID_SEQ_SIZE 256
-#define SDP_MAX_ATTR_LEN 65535
-
+#define MAX_IDENTIFIER_LEN 24
struct service_provider {
char *owner; /* null for remote services or unique name if local */
- bdaddr_t prov; /* remote Bluetooth address or local address */
+ char *prov; /* remote Bluetooth address thar provides the service */
+ int ttl; /* time to live */
struct slist *lrec;
};
struct service_record {
- uint32_t identifier;
+ int id;
sdp_record_t *record;
};
@@ -69,59 +68,114 @@ struct pending_connect {
DBusConnection *conn;
DBusMessage *rq;
char *svc;
- bdaddr_t dba;
+ char *dst;
};
struct transaction_context {
DBusConnection *conn;
DBusMessage *rq;
- char *svc;
sdp_session_t *session;
- sdp_cstate_t *cstate;
- uint8_t *reqbuf;
- bdaddr_t dba;
- sdp_buf_t rspbuf;
- uint32_t reqsize;
- int attr_list_len;
+};
+/* FIXME: move to a common file */
+typedef struct {
+ char *name;
+ uint16_t class;
+ char *info_name;
+} sdp_service_t;
+
+/* FIXME: move to a common file */
+sdp_service_t sdp_service[] = {
+ { "vcp", VIDEO_CONF_SVCLASS_ID, NULL },
+ { "map", 0, NULL },
+ { "pbap", 0, NULL },
+ { "sap", SAP_SVCLASS_ID, "SIM Access" },
+ { "ftp", OBEX_FILETRANS_SVCLASS_ID, "OBEX File Transfer" },
+ { "bpp", DIRECT_PRINTING_SVCLASS_ID, "Direct Printing" },
+ { "bip", 0, NULL },
+ { "synch", 0, NULL },
+ { "dun", DIALUP_NET_SVCLASS_ID, "Dial-Up Networking" },
+ { "opp", OBEX_OBJPUSH_SVCLASS_ID, "OBEX Object Push" },
+ { "fax", FAX_SVCLASS_ID, "Fax" },
+ { "spp", SERIAL_PORT_SVCLASS_ID, "Serial Port" },
+ { NULL }
};
-/* FIXME: store the arguments or just the pointer to the message */
+/* FIXME: move to a common file */
+uint16_t sdp_str2svclass(const char *str)
+{
+ sdp_service_t *s;
-/* list of remote and local service records
- * FIXME: free the cache when the local sock(sdpd) is closed
- */
+ for (s = sdp_service; s->name; s++) {
+ if (strcasecmp(s->name, str) == 0)
+ return s->class;
+ }
-static struct slist *sdp_cache = NULL;
-static struct slist *pending_connects = NULL;
+ return 0;
+}
-static const char *ecode2str(uint16_t ecode)
+/* FIXME: move to a common file */
+const char* sdp_svclass2str(uint16_t class)
{
- switch (ecode) {
- case 0x0000:
- return "Reserved";
- case 0x0001:
- return "Invalid/Unsupported SDP version";
- case 0x0002:
- return "Invalid Service Record Handle";
- case 0x0003:
- return "Invalid request syntax";
- case 0x0004:
- return "Invalid PDU size";
- case 0x0005:
- return "Invalid Continuation State";
- case 0x0006:
- return "Insufficient Resources to satisfy Request";
- default:
- return "Reserved";
+ sdp_service_t *s;
+
+ for (s = sdp_service; s->name; s++) {
+ if (s->class == class)
+ return s->name;
}
+
+ return NULL;
}
+/* FIXME: stub for bluez-libs changes */
+static inline sdp_session_t *sdp_session_new(int sk)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+/* FIXME: stub for bluez-libs changes */
+static inline int sdp_service_search_handle(sdp_session_t *session)
+{
+ return ENODATA;
+}
+
+/* FIXME: stub for bluez-libs changes */
+typedef void sdp_transaction_cb_t(sdp_list_t *rsp, void *udata, int err);
+static inline int sdp_service_search_attr_req_async(sdp_session_t *session, const sdp_list_t *search,
+ sdp_transaction_cb_t *f, void *udata)
+{
+ return 0;
+}
+
+/* FIXME: stub for service registration. Shared with sdptool */
+static inline sdp_record_t *sdp_service_register(const char *name, bdaddr_t *interface,
+ uint8_t channel, int *err)
+{
+ if (err)
+ *err = ENOSYS;
+
+ return NULL;
+}
+
+/* FIXME: stub for service registration. Shared with sdptool */
+static inline int sdp_service_unregister(bdaddr_t *interface, sdp_record_t *rec, int *err)
+{
+ if (err)
+ *err = ENOSYS;
+
+ return -1;
+}
+
+/* list of remote and local service records */
+static struct slist *sdp_cache = NULL;
+static struct slist *pending_connects = NULL;
+
static struct pending_connect *pending_connect_new(DBusConnection *conn, DBusMessage *msg,
- const bdaddr_t *bda, const char *svc)
+ const char *dst, const char *svc)
{
struct pending_connect *c;
- if (!bda)
+ if (!dst)
return NULL;
c = malloc(sizeof(*c));
@@ -131,18 +185,26 @@ static struct pending_connect *pending_connect_new(DBusConnection *conn, DBusMes
if (svc) {
c->svc = strdup(svc);
if (!c->svc)
- goto failed;
+ goto fail;
+ }
+ if (dst) {
+ c->dst = strdup(dst);
+ if (!c->dst)
+ goto fail;
}
- bacpy(&c->dba, bda);
c->conn = dbus_connection_ref(conn);
c->rq = dbus_message_ref(msg);
return c;
-failed:
- if (c)
- free(c);
+fail:
+ if (c->svc)
+ free(c->svc);
+ if (c->dst)
+ free(c->dst);
+ free(c);
+
return NULL;
}
@@ -163,237 +225,120 @@ static void pending_connect_free(struct pending_connect *c)
free(c);
}
-static struct pending_connect *find_pending_connect(const bdaddr_t *bda)
+static struct pending_connect *find_pending_connect(const char *dst)
{
struct slist *l;
for (l = pending_connects; l != NULL; l = l->next) {
struct pending_connect *pending = l->data;
- if (!bacmp(bda, &pending->dba))
+ if (!strcmp(dst, pending->dst))
return pending;
}
return NULL;
}
-/* FIXME: duplicated function. Make this function public on bluez-libs */
-static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd)
-{
- sdp_data_t *dataseq;
- void **types, **values;
- sdp_buf_t buf;
- int i, seqlen = sdp_list_len(seq);
-
- // Fill up the value and the dtd arrays
- memset(&buf, 0, sizeof(sdp_buf_t));
- buf.data = malloc(SDP_UUID_SEQ_SIZE);
- buf.buf_size = SDP_UUID_SEQ_SIZE;
-
- types = malloc(seqlen * sizeof(void *));
- values = malloc(seqlen * sizeof(void *));
- for (i = 0; i < seqlen; i++) {
- void *data = seq->data;
- types[i] = &dtd;
- if (SDP_IS_UUID(dtd))
- data = &((uuid_t *)data)->value;
- values[i] = data;
- seq = seq->next;
- }
-
- dataseq = sdp_seq_alloc(types, values, seqlen);
- seqlen = sdp_gen_pdu(&buf, dataseq);
- memcpy(dst, buf.data, buf.data_size);
- sdp_data_free(dataseq);
-
- free(types);
- free(values);
- free(buf.data);
- return seqlen;
-}
-
-/* FIXME: duplicated function */
-static int gen_searchseq_pdu(uint8_t *dst, const sdp_list_t *seq)
-{
- uuid_t *uuid = (uuid_t *) seq->data;
- return gen_dataseq_pdu(dst, seq, uuid->type);
-}
-
-/* FIXME: duplicated function */
-static int gen_attridseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dataType)
-{
- return gen_dataseq_pdu(dst, seq, dataType);
-}
-
-struct transaction_context *transaction_context_new(DBusConnection *conn, DBusMessage *msg, bdaddr_t *dba,
- const char *svc, int sock, uint32_t flags)
-{
- struct transaction_context *ctxt;
- sdp_pdu_hdr_t *reqhdr;
- sdp_list_t *pattern = NULL;
- sdp_list_t *attrids = NULL;
- uint8_t *pdata;
- uuid_t uuid;
- uint32_t range = 0x0000ffff;
- int seqlen;
-
- ctxt = malloc(sizeof(*ctxt));
- if (!ctxt)
- return NULL;
-
- memset(ctxt, 0, sizeof(*ctxt));
-
- if (svc) {
- ctxt->svc = strdup(svc);
- if (!ctxt->svc)
- goto failed;
- }
-
- if (dba)
- bacpy(&ctxt->dba, dba);
-
- ctxt->session = malloc(sizeof(sdp_session_t));
- if (!ctxt->session)
- goto failed;
-
- memset(ctxt->session, 0, sizeof(sdp_session_t));
-
- ctxt->conn = dbus_connection_ref(conn);
- ctxt->rq = dbus_message_ref(msg);
- ctxt->session->sock = sock;
- ctxt->session->flags = flags;
-
- ctxt->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
- if (!ctxt->reqbuf)
- goto failed;
-
- memset(ctxt->reqbuf, 0, SDP_REQ_BUFFER_SIZE);
-
- reqhdr = (sdp_pdu_hdr_t *) ctxt->reqbuf;
-
- reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;
- reqhdr->tid = 0;
-
- // Generate PDU
- pdata = ctxt->reqbuf + sizeof(sdp_pdu_hdr_t);
- ctxt->reqsize = sizeof(sdp_pdu_hdr_t);
-
- /* FIXME: it should be generic to handle other kind of search requests */
- sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
- pattern = sdp_list_append(0, &uuid);
- attrids = sdp_list_append(0, &range);
-
- seqlen = gen_searchseq_pdu(pdata, pattern);
-
- // set the length and increment the pointer
- ctxt->reqsize += seqlen;
- pdata +=seqlen;
-
- bt_put_unaligned(htons(SDP_MAX_ATTR_LEN), (uint16_t *) pdata);
- ctxt->reqsize += sizeof(uint16_t);
- pdata += sizeof(uint16_t);
-
- if (attrids) {
- seqlen = gen_attridseq_pdu(pdata, attrids, SDP_UINT32);
- if (seqlen == -1)
- goto failed;
-
- }
- if (pattern)
- sdp_list_free(pattern, 0);
- if (attrids)
- sdp_list_free(attrids, 0);
-
- pdata += seqlen;
- ctxt->reqsize += seqlen;
-
- reqhdr->plen = htons(ctxt->reqsize - sizeof(sdp_pdu_hdr_t));
-
- return ctxt;
-
-failed:
- if (ctxt->session)
- free(ctxt->session);
- if (ctxt->reqbuf)
- free(ctxt->reqbuf);
- free(ctxt);
-
- return NULL;
-}
-
-void transaction_context_free(struct transaction_context *ctxt)
+static int str2identifier(const char *identifier, char *address, int *id)
{
- if (!ctxt)
- return;
-
- if (ctxt->conn)
- dbus_connection_unref(ctxt->conn);
-
- if (ctxt->rq)
- dbus_message_unref(ctxt->rq);
-
- if (ctxt->svc)
- free(ctxt->svc);
+ if (!identifier || !address)
+ return -1;
- if (ctxt->session)
- free(ctxt->session);
+ if (strlen(identifier) < 19)
+ return -1;
- if (ctxt->reqbuf)
- free(ctxt->reqbuf);
+ memset(address, 0, 18);
- if (ctxt->rspbuf.data)
- free(ctxt->rspbuf.data);
+ snprintf(address, 18, "%s", identifier);
- free(ctxt);
+ return (sscanf(identifier + 18, "%d", id) > 0? 0: -1);
}
-/* FIXME: generate the pseudo random id */
-static uint32_t gen_next_id(const bdaddr_t *prov, uint32_t handle)
+static inline int gen_next_record_id()
{
- static uint32_t id;
- return ++id;
+ static int id = 0;
+ return id++;
}
-static struct service_record *service_record_new(const bdaddr_t *prov, sdp_record_t *rec)
+static struct service_record *service_record_new(sdp_record_t *rec)
{
struct service_record *r;
-
- if (!prov)
- return NULL;
r = malloc(sizeof(*r));
if (!r)
return NULL;
memset(r, 0, sizeof(*r));
- r->identifier = gen_next_id(prov, rec->handle);
+ r->id = gen_next_record_id();
r->record = rec;
return r;
}
-static void service_record_free(struct service_record *r, void *data)
+static void service_record_free(void *data, void *udata)
{
+ struct service_record *r = data;
+
if (!r)
return;
- sdp_record_free(r->record);
+ if (r->record)
+ sdp_record_free(r->record);
+
free(r);
}
-static void service_provider_free(struct service_provider *p)
+/*
+ * This function doesn't check service record pattern
+ */
+static int service_record_cmp(const void *data, const void *udata)
{
- if (p->owner)
- free(p->owner);
+ const struct service_record *a = data;
+ const struct service_record *b = udata;
+ if (b->id >= 0) {
+ if (a->id != b->id)
+ return -1;
+ }
- if (p->lrec) {
- slist_foreach(p->lrec, (slist_func_t)service_record_free, NULL);
- slist_free(p->lrec);
+ if (b->record) {
+ if (b->record->handle != 0xffffffff &&
+ b->record->handle != a->record->handle)
+ return -1;
}
- free(p);
+ return 0;
}
-static struct service_provider *service_provider_new(const char *owner, const bdaddr_t *prov)
+static void service_provider_free(void *data, void *udata)
+{
+ struct service_provider *p1 = data;
+ struct service_provider *p2 = udata;
+
+ if (!p1)
+ return;
+
+ /* Check if the provider match */
+ if (p2) {
+ if (p2->owner && strcmp(p2->owner, p1->owner))
+ return;
+ if (p2->prov && strcmp(p2->prov, p1->prov))
+ return;
+ }
+
+ if (p1->owner)
+ free(p1->owner);
+
+ if (p1->prov)
+ free(p1->prov);
+
+ if (p1->lrec) {
+ slist_foreach(p1->lrec, service_record_free, NULL);
+ slist_free(p1->lrec);
+ }
+
+ free(p1);
+}
+
+static struct service_provider *service_provider_new(const char *owner, const char *prov)
{
struct service_provider *p;
@@ -411,19 +356,25 @@ static struct service_provider *service_provider_new(const char *owner, const bd
goto fail;
}
- bacpy(&p->prov, prov);
+ if (prov) {
+ p->prov = strdup(prov);
+ if (!p->prov)
+ goto fail;
+ }
return p;
fail:
- service_provider_free(p);
+ service_provider_free(p, NULL);
return NULL;
}
-static int service_provider_cmp(const struct service_provider *a, const struct service_provider *b)
+static int service_provider_cmp(const void *data, const void *udata)
{
+ const struct service_provider *a = data;
+ const struct service_provider *b = udata;
int ret;
-
+
if (b->owner) {
if (!a->owner)
return -1;
@@ -432,10 +383,10 @@ static int service_provider_cmp(const struct service_provider *a, const struct s
return ret;
}
- if (bacmp(&b->prov, BDADDR_ANY)) {
- if (!bacmp(&a->prov, BDADDR_ANY))
+ if (b->prov) {
+ if (!a->prov)
return -1;
- ret = bacmp(&a->prov, &b->prov);
+ ret = strcmp(a->prov, b->prov);
if (ret)
return ret;
}
@@ -443,158 +394,98 @@ static int service_provider_cmp(const struct service_provider *a, const struct s
return 0;
}
-static uint32_t sdp_cache_append(const char *owner, const bdaddr_t *prov, sdp_record_t *rec)
+static int sdp_cache_append(const char *owner, const char *prov, sdp_record_t *rec)
{
- struct slist *l;
+ struct slist *lp, *lr;
struct service_provider *p;
- struct service_provider *ref;
+ struct service_provider psearch;
struct service_record *r;
-
- if (!prov || !rec)
- return 0;
- ref = service_provider_new(owner, prov);
- if (!ref)
- return 0;
+ if (!prov || !rec)
+ return -1;
- l = slist_find(sdp_cache, (const void*)ref, (cmp_func_t)service_provider_cmp);
- if (!l) {
+ memset(&psearch, 0, sizeof(psearch));
+ psearch.owner = (char *)owner;
+ psearch.prov = (char *)prov;
+
+ lp = slist_find(sdp_cache, &psearch, service_provider_cmp);
+ if (!lp) {
p = service_provider_new(owner, prov);
sdp_cache = slist_append(sdp_cache, p);
} else
- p = l->data;
-
- r = service_record_new(prov, rec);
- p->lrec = slist_append(p->lrec, r);
+ p = lp->data;
- if (ref)
- service_provider_free(ref);
+ /* check if there is service record already belongs to the cache */
+ r = malloc(sizeof(*r));
+ memset(r, 0, sizeof(*r));
+ r->id = -1;
+ r->record = sdp_record_alloc();
+ r->record->handle = rec->handle;
+ lr = slist_find(p->lrec, r, service_record_cmp);
+ service_record_free(r, NULL);
+
+ if (lr) {
+ /* overwrite the record instead of compare */
+ r = lr->data;
+ sdp_record_free(r->record);
+ r->record = rec;
+ } else {
+ /* create a new entry */
+ r = service_record_new(rec);
+ p->lrec = slist_append(p->lrec, r);
+ }
- return r->identifier;
+ return r->id;
}
static void owner_exited(const char *owner, struct hci_dbus_data *dbus_data)
{
- struct slist *cur, *next;
-
+ struct slist *lp, *next, *lr;
+ struct service_provider *p;
+ bdaddr_t sba;
+ int err = 0;
debug("SDP provider owner %s exited", owner);
- for (cur = sdp_cache; cur != NULL; cur = next) {
- struct service_provider *p = cur->data;
-
- next = cur->next;
+ for (lp = sdp_cache; lp; lp = next) {
- if(!p->owner)
- continue;
-
- if (strcmp(p->owner, owner))
+ next = lp->next;
+ p = lp->data;
+
+ if (!p->owner || strcmp(p->owner, owner))
continue;
- sdp_cache = slist_remove(sdp_cache, p);
- service_provider_free(p);
- }
-}
-
-/* FIXME: duplicated function */
-static int copy_cstate(uint8_t *pdata, const sdp_cstate_t *cstate)
-{
- if (cstate) {
- *pdata++ = cstate->length;
- memcpy(pdata, cstate->data, cstate->length);
- return cstate->length + 1;
- }
- *pdata = 0;
- return 1;
-}
-
-static int sdp_send_req(struct transaction_context *ctxt, int *err)
-{
- sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *) ctxt->reqbuf;
- uint32_t sent = 0;
- uint32_t reqsize;
-
- reqhdr->tid = htons(sdp_gen_tid(ctxt->session));
- reqsize = ctxt->reqsize + copy_cstate(ctxt->reqbuf + ctxt->reqsize, ctxt->cstate);
- reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
-
- while (sent < reqsize) {
- int n = send(ctxt->session->sock, ctxt->reqbuf + sent, reqsize - sent, 0);
- if (n < 0) {
- *err = errno;
- return -1;
+ /*
+ * Unregister all service records related to this owner.
+ * One owner can use multiple local adapter(provider)
+ */
+ str2ba(dbus_data->address, &sba);
+ for (lr = p->lrec; lr; lr = lr->next) {
+ struct service_record *r = lr->data;
+ if (sdp_service_unregister(&sba, r->record, &err) < 0)
+ error("unregister error: %s (%d)", strerror(err), err);
+ else
+ /* free inside the library */
+ r->record = NULL;
}
- sent += n;
- }
- return 0;
-}
-
-static DBusMessage *parse_response(struct transaction_context *ctxt)
-{
- DBusMessage *reply = NULL;
- DBusMessageIter iter;
- DBusMessageIter array_iter;
- int scanned, seqlen;
- uint8_t dataType;
- uint8_t *pdata;
- const char *owner;
-
- owner = dbus_message_get_sender(ctxt->rq);
-
- reply = dbus_message_new_method_return(ctxt->rq);
-
- if ((ctxt->attr_list_len <= 0) || (ctxt->rspbuf.data_size == 0))
- return dbus_message_new_error(ctxt->rq, ERROR_INTERFACE ".DoesNotExist",
- "Record does not exist");
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_UINT32_AS_STRING, &array_iter);
-
- pdata = ctxt->rspbuf.data;
-
- scanned = sdp_extract_seqtype(pdata, &dataType, &seqlen);
-
- if (scanned && seqlen) {
- pdata += scanned;
- do {
- uint32_t id;
- int recsize = 0;
- sdp_record_t *rec = sdp_extract_pdu(pdata, &recsize);
- if (rec == NULL)
- break;
-
- if (!recsize) {
- sdp_record_free(rec);
- break;
- }
-
- scanned += recsize;
- pdata += recsize;
-
- id = sdp_cache_append(owner, &ctxt->dba, rec);
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_UINT32, &id);
+ /* remove from the cache */
+ sdp_cache = slist_remove(sdp_cache, p);
- } while (scanned < ctxt->attr_list_len);
+ service_provider_free(p, NULL);
}
-
- dbus_message_iter_close_container(&iter, &array_iter);
-
- return reply;
}
-static gboolean svc_search_attr_req_cb(GIOChannel *chan, GIOCondition cond, struct transaction_context *ctxt)
+static gboolean search_session_handle_cb(GIOChannel *chan, GIOCondition cond, void *udata)
{
- int sk, err, n;
- uint32_t rsp_count;
- gboolean ret_val = FALSE;
+ struct transaction_context *ctxt = udata;
+ int sk, err = 0;
socklen_t len;
- uint8_t cstate_len;
- uint8_t *pdata;
- uint8_t *rsp = NULL;
- sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *) ctxt->reqbuf;
- sdp_pdu_hdr_t *rsphdr;
+ const char *dst;
+ int retval = FALSE;
+
+ dbus_message_get_args(ctxt->rq, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_INVALID);
sk = g_io_channel_unix_get_fd(chan);
@@ -602,84 +493,96 @@ static gboolean svc_search_attr_req_cb(GIOChannel *chan, GIOCondition cond, stru
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
error("getsockopt(): %s, (%d)", strerror(errno), errno);
- goto failed;
+ error_failed(ctxt->conn, ctxt->rq, errno);
+ goto fail;
}
if (err != 0) {
- error("connect(): %s(%d)", strerror(err), err);
- error_connection_attempt_failed(ctxt->conn, ctxt->rq, err);
- goto failed;
+ error_failed(ctxt->conn, ctxt->rq, err);
+ error("sock error:s(%d)", strerror(err), err);
+ goto fail;
}
+ if (!sdp_service_search_handle(ctxt->session))
+ return TRUE;
- rsp = malloc(SDP_RSP_BUFFER_SIZE);
- memset(rsp, 0, SDP_RSP_BUFFER_SIZE);
+fail:
+ g_io_channel_close(chan);
+ return retval;
+}
- n = recv(sk, rsp, SDP_RSP_BUFFER_SIZE, 0);
- if (n <= 0) {
- err = errno;
- goto failed;
- }
+static void search_transaction_completed_cb(sdp_list_t *rsp, struct transaction_context *ctxt, int err)
+{
+ char identifier[MAX_IDENTIFIER_LEN];
+ const char *ptr = identifier;
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ sdp_list_t *next;
+ const char *dst;
+ int id;
- rsphdr = (sdp_pdu_hdr_t *)rsp;
- if (n == 0 || reqhdr->tid != rsphdr->tid) {
- err = EPROTO;
- goto failed;
+ if (!ctxt)
+ return;
+
+ if (err) {
+ error_failed(ctxt->conn, ctxt->rq, err);
+ return;
}
- pdata = rsp + sizeof(sdp_pdu_hdr_t);
+ dbus_message_get_args(ctxt->rq, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_INVALID);
- if (rsphdr->pdu_id == SDP_ERROR_RSP) {
- uint16_t ecode = ntohs(bt_get_unaligned((uint16_t *) pdata));
- error("Received SDP error response PDU: %s (%d)", ecode2str(ecode), ecode);
- err = EPROTO;
- goto failed;
- }
+ reply = dbus_message_new_method_return(ctxt->rq);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
- rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
- ctxt->attr_list_len += rsp_count;
- pdata += sizeof(uint16_t);
+ /* add in the cache */
+ for ( ;rsp; rsp = next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
- // if continuation state set need to re-issue request before parsing
- cstate_len = *(uint8_t *) (pdata + rsp_count);
+ id = sdp_cache_append(NULL, dst, rec);
+ snprintf(identifier, MAX_IDENTIFIER_LEN, "%s/%d", dst, id);
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &ptr);
- if (rsp_count > 0) {
- uint8_t *targetPtr = NULL;
+ next = rsp->next;
+ free(rsp);
+ /* Don't free the record */
+ }
- ctxt->cstate = cstate_len > 0 ? (sdp_cstate_t *) (pdata + rsp_count) : 0;
+ dbus_message_iter_close_container(&iter, &array_iter);
+ send_reply_and_unref(ctxt->conn, reply);
+}
- // build concatenated response buffer
- ctxt->rspbuf.data = realloc(ctxt->rspbuf.data, ctxt->rspbuf.data_size + rsp_count);
- ctxt->rspbuf.buf_size = ctxt->rspbuf.data_size + rsp_count;
- targetPtr = ctxt->rspbuf.data + ctxt->rspbuf.data_size;
- memcpy(targetPtr, pdata, rsp_count);
- ctxt->rspbuf.data_size += rsp_count;
- }
+static void transaction_context_free(void *udata)
+{
+ struct transaction_context *ctxt = udata;
- if (ctxt->cstate) {
- if (!sdp_send_req(ctxt, &err))
- ret_val = TRUE;
- } else {
- /* parse the response PDU */
- send_reply_and_unref(ctxt->conn, parse_response(ctxt));
- }
-failed:
- if (rsp)
- free(rsp);
+ if (!ctxt)
+ return;
- if (err) {
- error_failed(ctxt->conn, ctxt->rq, err);
- error("SDP transaction error: %s (%d)", strerror(err), err);
- }
+ if (ctxt->conn)
+ dbus_connection_unref(ctxt->conn);
+
+ if (ctxt->rq)
+ dbus_message_unref(ctxt->rq);
- return ret_val;
+ if (ctxt->session)
+ sdp_close(ctxt->session);
+
+ free(ctxt);
}
-static gboolean sdp_client_connect_cb(GIOChannel *chan, GIOCondition cond, struct pending_connect *c)
+static gboolean sdp_client_connect_cb(GIOChannel *chan, GIOCondition cond, void *udata)
{
- int err, sk = 0;
+ struct pending_connect *c = udata;
+ struct transaction_context *ctxt = NULL;
+ sdp_list_t *search = NULL;
+ uint16_t class;
+ int err = 0, sk = 0;
socklen_t len;
- GIOChannel *tchan;
- struct transaction_context *ctxt;
+ uuid_t uuid;
sk = g_io_channel_unix_get_fd(chan);
@@ -687,33 +590,62 @@ static gboolean sdp_client_connect_cb(GIOChannel *chan, GIOCondition cond, struc
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
error("getsockopt(): %s, (%d)", strerror(errno), errno);
- goto failed;
+ error_connection_attempt_failed(c->conn, c->rq, errno);
+ goto fail;
}
if (err != 0) {
error("connect(): %s(%d)", strerror(err), err);
error_connection_attempt_failed(c->conn, c->rq, err);
- goto failed;
+ goto fail;
}
- ctxt = transaction_context_new(c->conn, c->rq, &c->dba, c->svc, sk, 0);
-
+ ctxt = malloc(sizeof(*ctxt));
if (!ctxt) {
error_failed(c->conn, c->rq, ENOMEM);
- goto failed;
+ goto fail;
}
+ memset(ctxt, 0, sizeof(*ctxt));
- tchan = g_io_channel_unix_new(sk);
+ /* FIXME: the sdp search list pattern should be created outside */
+ if (!c->svc) {
+ sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
+ search = sdp_list_append(0, &uuid);
+ } else {
+ class = sdp_str2svclass(c->svc);
+ sdp_uuid16_create(&uuid, class);
+ search = sdp_list_append(0, &uuid);
+ }
- g_io_add_watch_full(tchan, 0, G_IO_IN, (GIOFunc)svc_search_attr_req_cb,
- ctxt, (GDestroyNotify)transaction_context_free);
+ ctxt->conn = dbus_connection_ref(c->conn);
+ ctxt->rq = dbus_message_ref(c->rq);
+ ctxt->session = sdp_session_new(sk);
+ if (!ctxt->session) {
+ error("error: %s (%d)", strerror(errno), errno);
+ error_failed(c->conn, c->rq, errno);
+ goto fail;
+ }
- if (sdp_send_req(ctxt, &err) < 0) {
- error("Can't send PDU: %s (%d)", strerror(err), err);
- error_failed(c->conn, c->rq, err);
- goto failed;
+ /* Create/send the search request and set the callback to indicate the request completion */
+ if (sdp_service_search_attr_req_async(ctxt->session, search,
+ (sdp_transaction_cb_t *)search_transaction_completed_cb, ctxt) < 0) {
+ error("send request failed: %s (%d)", strerror(errno), errno);
+ error_failed(c->conn, c->rq, errno);
+ goto fail;
}
-failed:
+
+ /* set the callback responsible for update the transaction data */
+ g_io_add_watch_full(chan, 0, G_IO_IN, search_session_handle_cb,
+ ctxt, transaction_context_free);
+ goto done;
+
+fail:
+ if (ctxt)
+ transaction_context_free(ctxt);
+done:
+ if (search)
+ sdp_list_free(search, 0);
+
pending_connects = slist_remove(pending_connects, c);
pending_connect_free(c);
@@ -725,11 +657,11 @@ static int search_request(DBusConnection *conn, DBusMessage *msg, uint16_t dev_i
{
struct pending_connect *c = NULL;
GIOChannel *chan = NULL;
- bdaddr_t sba;
struct sockaddr_l2 sa;
int sk, watch = 0;
// create L2CAP connection
+ /* FIXME: use set_nonblocking */
sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (sk < 0) {
if (err)
@@ -743,21 +675,18 @@ static int search_request(DBusConnection *conn, DBusMessage *msg, uint16_t dev_i
sa.l2_family = AF_BLUETOOTH;
sa.l2_psm = 0;
- hci_devba(dev_id, &sba);
+ hci_devba(dev_id, &sa.l2_bdaddr);
- if (bacmp(&sba, BDADDR_ANY) != 0) {
- bacpy(&sa.l2_bdaddr, &sba);
- if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
- if (err)
- *err = errno;
- goto fail;
- }
+ if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ if (err)
+ *err = errno;
+ goto fail;
}
sa.l2_psm = htobs(SDP_PSM);
str2ba(dst, &sa.l2_bdaddr);
- c = pending_connect_new(conn, msg, &sa.l2_bdaddr, svc);
+ c = pending_connect_new(conn, msg, dst, svc);
if (!c) {
if (err)
*err = ENOMEM;
@@ -766,7 +695,7 @@ static int search_request(DBusConnection *conn, DBusMessage *msg, uint16_t dev_i
fcntl(sk, F_SETFL, fcntl(sk, F_GETFL, 0)|O_NONBLOCK);
if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
- if ( !(errno == EAGAIN || errno == EINPROGRESS)) {
+ if (!(errno == EAGAIN || errno == EINPROGRESS)) {
if (err)
*err = errno;
error("connect() failed:%s (%d)", strerror(errno), errno);
@@ -774,7 +703,7 @@ static int search_request(DBusConnection *conn, DBusMessage *msg, uint16_t dev_i
}
watch = g_io_add_watch(chan, G_IO_OUT,
- (GIOFunc)sdp_client_connect_cb, c);
+ sdp_client_connect_cb, c);
pending_connects = slist_append(pending_connects, c);
} else {
sdp_client_connect_cb(chan, G_IO_OUT, c);
@@ -796,60 +725,59 @@ static DBusHandlerResult get_identifiers(DBusConnection *conn,
{
char filename[PATH_MAX + 1];
struct hci_dbus_data *dbus_data = data;
- struct service_provider *p;
- struct slist *l;
const char *dst;
char *str;
- DBusMessage *reply;
- DBusMessageIter iter, array_iter;
- bdaddr_t dba;
int err = 0;
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_STRING, &dst,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
-
- /* FIXME: validate Bluetooth address(dst) */
-
- str2ba(dst, &dba);
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ if (find_pending_connect(dst))
+ return error_service_search_in_progress(conn, msg);
- p = service_provider_new(NULL, &dba);
- if (!p) {
- dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
- }
-
- l = slist_find(sdp_cache, p, (cmp_func_t)service_provider_cmp);
- service_provider_free(p);
+ /* check if it is a unknown address */
+ snprintf(filename, PATH_MAX, "%s/%s/lastseen", STORAGEDIR, dbus_data->address);
- if (l) {
- struct slist *lr;
- struct service_record *r;
+ str = textfile_get(filename, dst);
+ if (!str)
+ return error_unknown_address(conn, msg);
- /* check the cache */
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_UINT32_AS_STRING, &array_iter);
+ free(str);
- p = l->data;
- for (lr = p->lrec; lr; lr = lr->next) {
- r = lr->data;
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_UINT32, &r->identifier);
- }
+ if (search_request(conn, msg, dbus_data->dev_id, dst, NULL, &err) < 0) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ return error_failed(conn, msg, err);
+ }
- dbus_message_iter_close_container(&iter, &array_iter);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
- return send_reply_and_unref(conn, reply);
- }
+static DBusHandlerResult get_identifiers_by_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ char filename[PATH_MAX + 1];
+ struct hci_dbus_data *dbus_data = data;
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ struct slist *lp;
+ struct slist *lr;
+ struct service_provider *p;
+ struct service_record *r;
+ char identifier[MAX_IDENTIFIER_LEN];
+ const char *ptr = identifier;
+ const char *dst, *svc;
+ char *str;
+ int err = 0, nrec = 0;
+ uint32_t class;
+ uuid_t uuid;
- if (find_pending_connect(&dba))
- return error_service_search_in_progress(conn, msg);
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_STRING, &svc,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
/* check if it is a unknown address */
create_name(filename, PATH_MAX, STORAGEDIR, dbus_data->address, "lastseen");
@@ -860,21 +788,74 @@ static DBusHandlerResult get_identifiers(DBusConnection *conn,
free(str);
- if (search_request(conn, msg, dbus_data->dev_id, dst, NULL, &err) < 0) {
+ class = sdp_str2svclass(svc);
+ if (!class) {
+ error("Invalid service class name");
+ return error_invalid_arguments(conn, msg);
+ }
+
+ sdp_uuid16_create(&uuid, class);
+
+ p = service_provider_new(NULL, dst);
+ if (!p)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ /* FIXME: return cache entry or query again? */
+ lp = slist_find(sdp_cache, p, service_provider_cmp);
+ service_provider_free(p, NULL);
+
+ if (!lp)
+ goto search_request;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ p = lp->data;
+ for (lr = p->lrec; lr; lr = lr->next) {
+ sdp_list_t *ls;
+ uuid_t *puuid;
+ r = lr->data;
+ /* check if the pattern match */
+ if (sdp_get_service_classes(r->record, &ls))
+ continue;
+
+ puuid = (uuid_t *)ls->data;
+
+ if (sdp_uuid16_cmp(puuid, &uuid) == 0) {
+ snprintf(identifier, MAX_IDENTIFIER_LEN, "%s/%d", p->prov, r->id);
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &ptr);
+ nrec++;
+ }
+
+ sdp_list_free(ls, free);
+
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ if (nrec > 0)
+ return send_reply_and_unref(conn, reply);
+
+ /* no record found: request search */
+ dbus_message_unref(reply);
+
+search_request:
+ if (find_pending_connect(dst))
+ return error_service_search_in_progress(conn, msg);
+
+ if (search_request(conn, msg, dbus_data->dev_id, dst, svc, &err) < 0) {
error("Search request failed: %s (%d)", strerror(err), err);
return error_failed(conn, msg, err);
}
return DBUS_HANDLER_RESULT_HANDLED;
-}
-static DBusHandlerResult get_identifiers_by_service(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
-sdp_record_t *find_record(uint32_t identifier)
+static sdp_record_t *find_record(const char *address, int id)
{
struct slist *lp, *lr;
struct service_provider *p;
@@ -882,9 +863,12 @@ sdp_record_t *find_record(uint32_t identifier)
for (lp = sdp_cache; lp; lp = lp->next) {
p = lp->data;
+ if (strcmp(p->prov, address))
+ continue;
+
for (lr = p->lrec; lr; lr = lr->next) {
r = lr->data;
- if (r->identifier == identifier)
+ if (r->id == id)
return r->record;
}
}
@@ -896,18 +880,23 @@ static DBusHandlerResult get_uuid(DBusConnection *conn,
DBusMessage *msg, void *data)
{
char uuid_str[MAX_LEN_UUID_STR];
- sdp_list_t *l;
+ char address[18];
+ sdp_list_t *ls;
DBusMessage *reply;
sdp_record_t *rec;
char *ptr = uuid_str;
- uint32_t identifier;
+ const char *identifier;
+ int id;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_UINT32, &identifier,
+ DBUS_TYPE_STRING, &identifier,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- rec = find_record(identifier);
+ if (str2identifier(identifier, address, &id) != 0)
+ return error_invalid_arguments(conn, msg);
+
+ rec = find_record(address, id);
if (!rec)
return error_record_does_not_exist(conn, msg);
@@ -915,11 +904,16 @@ static DBusHandlerResult get_uuid(DBusConnection *conn,
reply = dbus_message_new_method_return(msg);
- if (sdp_get_profile_descs(rec, &l) == 0) {
- sdp_profile_desc_t *desc = (sdp_profile_desc_t *)l->data;
+ if (sdp_get_service_classes(rec, &ls) == 0) {
+ char tmp_str[MAX_LEN_UUID_STR];
+ uuid_t *uuid = (uuid_t *)ls->data;
- sdp_uuid2strn(&desc->uuid, uuid_str, MAX_LEN_UUID_STR);
- sdp_list_free(l, free);
+ if (sdp_uuid2strn(uuid, tmp_str, MAX_LEN_UUID_STR) != 0)
+ error("Can't convert UUID to string!");
+ else
+ snprintf(uuid_str, MAX_LEN_UUID_STR, "0x%s", tmp_str);
+
+ sdp_list_free(ls, free);
}
dbus_message_append_args(reply,
@@ -932,27 +926,43 @@ static DBusHandlerResult get_uuid(DBusConnection *conn,
static DBusHandlerResult get_name(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ char address[18];
DBusMessage *reply;
sdp_record_t *rec;
- sdp_data_t *d;
+ sdp_list_t *ls;
char name[] = "";
- char *ptr = name;
- uint32_t identifier;
+ const char *ptr = name;
+ const char *identifier;
+ uuid_t *puuid;
+ int id;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_UINT32, &identifier,
+ DBUS_TYPE_STRING, &identifier,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- rec = find_record(identifier);
+ if (str2identifier(identifier, address, &id) != 0)
+ return error_invalid_arguments(conn, msg);
+
+ rec = find_record(address, id);
if (!rec)
return error_record_does_not_exist(conn, msg);
- reply = dbus_message_new_method_return(msg);
- d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
- if (d && d->val.str)
- ptr = d->val.str;
+ if ((sdp_get_service_classes(rec, &ls)) < 0) {
+ return error_failed(conn, msg, errno);
+ }
+
+ puuid = (uuid_t *)ls->data;
+ ptr = sdp_svclass2str(puuid->value.uuid16);
+ sdp_list_free(ls, free);
+
+ /* return empty string for non supported services */
+ if (!ptr)
+ ptr = name;
+
+ /* FIXME: it should return the service name attribute instead of the short service name */
+ reply = dbus_message_new_method_return(msg);
dbus_message_append_args(reply,
DBUS_TYPE_STRING, &ptr,
DBUS_TYPE_INVALID);
@@ -964,11 +974,14 @@ static DBusHandlerResult register_rfcomm(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct hci_dbus_data *dbus_data = data;
- struct service_provider ref;
+ struct service_provider psearch;
DBusMessage *reply;
+ sdp_record_t *rec;
const char *owner, *name;
+ char identifier[MAX_IDENTIFIER_LEN];
+ const char *ptr = identifier;
bdaddr_t sba;
- uint32_t identifier = 0, handle = 0;
+ int id = 0, err = 0;
uint8_t channel;
owner = dbus_message_get_sender(msg);
@@ -979,39 +992,51 @@ static DBusHandlerResult register_rfcomm(DBusConnection *conn,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- /* FIXME: register the service */
-
- hci_devba(dbus_data->dev_id, &sba);
- identifier = gen_next_id(&sba, handle);
-
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- dbus_message_append_args(msg,
- DBUS_TYPE_UINT32, &identifier,
- DBUS_TYPE_INVALID);
+ str2ba(dbus_data->address, &sba);
+ /* register service */
+ if (!(rec = sdp_service_register(name, &sba, channel, &err))) {
+ dbus_message_unref(reply);
+ error("service register error: %s (%d)", strerror(err), err);
+ if (err == EINVAL)
+ return error_invalid_arguments(conn, msg);
+ else
+ return error_failed(conn, msg, err);
+ }
/* Only add a D-Bus unique name listener if there isn't one already registered */
- memset(&ref, 0, sizeof(ref));
- bacpy(&ref.prov, BDADDR_ANY);
+ memset(&psearch, 0, sizeof(psearch));
+ psearch.owner = (char *)owner;
- if (!slist_find(sdp_cache, &ref, (cmp_func_t)service_provider_cmp))
+ if (!slist_find(sdp_cache, &psearch, service_provider_cmp))
name_listener_add(conn, owner, (name_cb_t)owner_exited, dbus_data);
- /* FIXME: register the RFCOMM service */
-
+ /* add record in the cache */
+ id = sdp_cache_append(owner, dbus_data->address, rec);
+
+ snprintf(identifier, MAX_IDENTIFIER_LEN, "%s/%d", dbus_data->address, id);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+
return send_reply_and_unref(conn, reply);
}
static DBusHandlerResult unregister_rfcomm(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ char address[18];
struct hci_dbus_data *dbus_data = data;
- struct service_provider *p, ref;
- struct slist *match;
+ struct service_provider *p, psearch;
+ struct service_record rsearch, *r;
+ struct slist *lp, *lr;
DBusMessage *reply;
const char *owner, *identifier;
+ bdaddr_t sba;
+ int id = 0, err = 0;
owner = dbus_message_get_sender(msg);
@@ -1020,34 +1045,55 @@ static DBusHandlerResult unregister_rfcomm(DBusConnection *conn,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- memset(&ref, 0, sizeof(ref));
-
- hci_devba(dbus_data->dev_id, &ref.prov);
- ref.owner = (char *) owner;
+ if (str2identifier(identifier, address, &id) != 0)
+ return error_invalid_arguments(conn, msg);
+
+ /* check if the local adapter match */
+ if (strcmp(address, dbus_data->address))
+ return error_not_authorized(conn, msg);
- match = slist_find(sdp_cache, &ref, (cmp_func_t)service_provider_cmp);
- if (!match)
+ memset(&psearch, 0, sizeof(psearch));
+
+ psearch.prov = address;
+ psearch.owner = (char *)owner;
+
+ lp = slist_find(sdp_cache, &psearch, service_provider_cmp);
+ if (!lp)
return error_service_does_not_exist(conn, msg);
- /* FIXME: find the RFCOMM UUID in the list */
- p = match->data;
-
- if (strcmp(p->owner, owner))
- return error_not_authorized(conn, msg);
+ p = lp->data;
+
+ memset(&rsearch, 0, sizeof(rsearch));
+ rsearch.id = id;
+ str2ba(dbus_data->address, &sba);
+ lr = slist_find(p->lrec, &rsearch, service_record_cmp);
+ if (!lr)
+ return error_service_does_not_exist(conn, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- /* FIXME: unregister the service */
+ r = lr->data;
+ if (sdp_service_unregister(&sba, r->record, &err) < 0)
+ error("service unregister error: %s (%d)", strerror(err), err);
+ else
+ r->record = NULL;
- sdp_cache = slist_remove(sdp_cache, p);
- service_provider_free(p);
+ /* Remove the service record */
+ service_record_free(r, NULL);
+ p->lrec = slist_remove(p->lrec, r);
- bacpy(&ref.prov, BDADDR_ANY);
+ /* if the service record is empty remove the provider */
+ if (!p->lrec) {
+ sdp_cache = slist_remove(sdp_cache, p);
+ service_provider_free(p, NULL);
+ }
+
+ psearch.prov = NULL;
/* Only remove the D-Bus unique name listener if there are no more record using this name */
- if (!slist_find(sdp_cache, &ref, (cmp_func_t)service_provider_cmp))
+ if (!slist_find(sdp_cache, &psearch, service_provider_cmp))
name_listener_remove(conn, owner, (name_cb_t)owner_exited, dbus_data);
return send_reply_and_unref(conn, reply);
@@ -1077,3 +1123,8 @@ DBusHandlerResult handle_sdp_method(DBusConnection *conn, DBusMessage *msg, void
return error_unknown_method(conn, msg);
}
+
+void dbus_sdp_cache_free()
+{
+ slist_foreach(sdp_cache, service_provider_free, NULL);
+}