summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlisses Furquim <ulissesf@gmail.com>2006-09-19 16:50:05 +0000
committerUlisses Furquim <ulissesf@gmail.com>2006-09-19 16:50:05 +0000
commit420ad4437afc127331e029c63df8e9e9d572d9b6 (patch)
treee04c8a333498de8054b184e85ed2fda245a1c510
parent265dbd3308253a1f94fe43c27c1d65f0059df77a (diff)
Make RFCOMM.Connect() do an SDP search before connecting
-rw-r--r--hcid/dbus-rfcomm.c298
-rw-r--r--hcid/dbus-sdp.c436
-rw-r--r--hcid/dbus.h9
3 files changed, 571 insertions, 172 deletions
diff --git a/hcid/dbus-rfcomm.c b/hcid/dbus-rfcomm.c
index 1258f337..88984027 100644
--- a/hcid/dbus-rfcomm.c
+++ b/hcid/dbus-rfcomm.c
@@ -117,7 +117,8 @@ static struct rfcomm_node *find_node_by_name(struct slist *nodes, const char *na
return NULL;
}
-static struct pending_connect *find_pending_connect(const char *bda, uint8_t ch)
+static struct pending_connect *find_pending_connect_by_channel(const char *bda,
+ uint8_t ch)
{
struct slist *l;
bdaddr_t dba;
@@ -126,8 +127,26 @@ static struct pending_connect *find_pending_connect(const char *bda, uint8_t ch)
for (l = pending_connects; l != NULL; l = l->next) {
struct pending_connect *pending = l->data;
- if (!bacmp(&dba, &pending->raddr.rc_bdaddr)
- && pending->raddr.rc_channel == ch)
+ if (!bacmp(&dba, &pending->raddr.rc_bdaddr) &&
+ pending->raddr.rc_channel == ch)
+ return pending;
+ }
+
+ return NULL;
+}
+
+static struct pending_connect *find_pending_connect_by_service(const char *bda,
+ const char *svc)
+{
+ struct slist *l;
+ bdaddr_t dba;
+
+ str2ba(bda, &dba);
+
+ for (l = pending_connects; l != NULL; l = l->next) {
+ struct pending_connect *pending = l->data;
+ if (!bacmp(&dba, &pending->raddr.rc_bdaddr) &&
+ !strcmp(pending->svc, svc))
return pending;
}
@@ -329,7 +348,6 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond,
error_failed(c->conn, c->msg, err);
goto failed;
}
-
if (ret != 0) {
error("connect(): %s (%d)", strerror(ret), ret);
error_connection_attempt_failed(c->conn, c->msg, ret);
@@ -407,7 +425,6 @@ static int rfcomm_connect(DBusConnection *conn, DBusMessage *msg, bdaddr_t *src,
*err = ENOMEM;
goto failed;
}
-
memset(c, 0, sizeof(struct pending_connect));
if (svc) {
@@ -516,133 +533,222 @@ static struct rfcomm_node *rfcomm_bind(bdaddr_t *src, const char *bda, uint8_t c
return node;
}
-static sdp_record_t *get_record_from_string(const char *dst,
- const char *string)
+typedef struct {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ char *dst;
+ char *svc;
+ struct hci_dbus_data *dbus_data;
+} rfcomm_conn_cont_data_t;
+
+static rfcomm_conn_cont_data_t *rfcomm_conn_cont_data_new(DBusConnection *conn,
+ DBusMessage *msg,
+ const char *dst,
+ const char *svc,
+ struct hci_dbus_data *dbus_data)
+{
+ rfcomm_conn_cont_data_t *new;
+
+ new = malloc(sizeof(*new));
+ if (!new)
+ return NULL;
+
+ new->dst = strdup(dst);
+ if (!new->dst) {
+ free(new);
+ return NULL;
+ }
+
+ new->svc = strdup(svc);
+ if (!new->svc) {
+ free(new->dst);
+ free(new);
+ return NULL;
+ }
+
+ new->conn = dbus_connection_ref(conn);
+ new->msg = dbus_message_ref(msg);
+ new->dbus_data = dbus_data;
+
+ return new;
+}
+
+static void rfcomm_conn_cont_data_free(rfcomm_conn_cont_data_t *d)
{
+ dbus_connection_unref(d->conn);
+ dbus_message_unref(d->msg);
+ free(d->svc);
+ free(d->dst);
+ free(d);
+}
+
+static void rfcomm_conn_req_continue(sdp_record_t *rec, void *data, int err)
+{
+ rfcomm_conn_cont_data_t *cdata = data;
+ int ch = -1, conn_err;
+ sdp_list_t *protos;
+ bdaddr_t bdaddr;
+
+ if (err || !rec) {
+ error_record_does_not_exist(cdata->conn, cdata->msg);
+ goto failed;
+ }
+
+ if (!sdp_get_access_protos(rec, &protos))
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ if (ch == -1) {
+ error_record_does_not_exist(cdata->conn, cdata->msg);
+ goto failed;
+ }
+
+ if (find_pending_connect_by_channel(cdata->dst, ch)) {
+ error_connect_in_progress(cdata->conn, cdata->msg);
+ goto failed;
+ }
+
+ hci_devba(cdata->dbus_data->dev_id, &bdaddr);
+ if (rfcomm_connect(cdata->conn, cdata->msg, &bdaddr,
+ cdata->dst, cdata->svc, ch, &conn_err) < 0)
+ error_failed(cdata->conn, cdata->msg, conn_err);
+
+failed:
+ rfcomm_conn_cont_data_free(cdata);
+}
+
+static uuid_t *str2uuid128(const char *string)
+{
+ uint16_t data1, data2, data3, data5;
+ uint32_t data0, data4;
uuid_t short_uuid;
- uuid_t *uuid;
- sdp_record_t *rec;
- unsigned int data0, data4;
- unsigned short data1, data2, data3, data5;
- uint32_t handle;
- /* Check if the string is a service name */
sdp_uuid16_create(&short_uuid, sdp_str2svclass(string));
-
- if (short_uuid.value.uuid16) {
- rec = find_record_by_uuid(dst, &short_uuid);
- } else if (sscanf(string, "%8x-%4hx-%4hx-%4hx-%8x%4hx", &data0,
- &data1, &data2, &data3, &data4, &data5) == 6) {
+ if (short_uuid.value.uuid16)
+ return sdp_uuid_to_uuid128(&short_uuid);
+
+ if (strlen(string) == 36 &&
+ string[8] == '-' &&
+ string[13] == '-' &&
+ string[18] == '-' &&
+ string[23] == '-' &&
+ sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
+ &data0, &data1, &data2, &data3, &data4, &data5) == 6) {
+ uint8_t val[16];
+ uuid_t *uuid;
+
+ uuid = malloc(sizeof(*uuid));
+ if (!uuid)
+ return NULL;
+
data0 = htonl(data0);
data1 = htons(data1);
data2 = htons(data2);
data3 = htons(data3);
data4 = htonl(data4);
data5 = htons(data5);
-
- uuid = bt_malloc(sizeof(uuid_t));
- uuid->type = SDP_UUID128;
-
- memcpy(&uuid->value.uuid128.data[0], &data0, 4);
- memcpy(&uuid->value.uuid128.data[4], &data1, 2);
- memcpy(&uuid->value.uuid128.data[6], &data2, 2);
- memcpy(&uuid->value.uuid128.data[8], &data3, 2);
- memcpy(&uuid->value.uuid128.data[10], &data4, 4);
- memcpy(&uuid->value.uuid128.data[14], &data5, 2);
-
- rec = find_record_by_uuid(dst, uuid);
-
- bt_free(uuid);
- } else if ((handle = strtol(string, NULL, 0)))
- rec = find_record_by_handle(dst, handle);
- else
- rec = NULL;
-
- return rec;
+
+ memcpy(&val[0], &data0, 4);
+ memcpy(&val[4], &data1, 2);
+ memcpy(&val[6], &data2, 2);
+ memcpy(&val[8], &data3, 2);
+ memcpy(&val[10], &data4, 4);
+ memcpy(&val[14], &data5, 2);
+
+ return sdp_uuid128_create(uuid, val);
+ }
+
+ return NULL;
+}
+
+static uint32_t *str2handle(const char *string)
+{
+ uint32_t *handle;
+
+ handle = malloc(sizeof(*handle));
+ if (!handle)
+ return NULL;
+
+ *handle = strtol(string, NULL, 0);
+ if (*handle)
+ return handle;
+
+ free(handle);
+ return NULL;
}
static DBusHandlerResult rfcomm_connect_req(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- int ch = -1;
- const char *dst;
- const char *string;
- sdp_record_t *rec;
- sdp_list_t *protos;
- bdaddr_t bdaddr;
struct hci_dbus_data *dbus_data = data;
+ rfcomm_conn_cont_data_t *cdata;
+ uint32_t *handle = NULL;
+ uuid_t *uuid = NULL;
+ const char *string;
+ const char *dst;
int err;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &dst,
- DBUS_TYPE_STRING, &string,
- DBUS_TYPE_INVALID))
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_STRING, &string,
+ DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- hci_devba(dbus_data->dev_id, &bdaddr);
-
- rec = get_record_from_string(dst, string);
-
- if (!rec)
- return error_record_does_not_exist(conn, msg);
-
- if (sdp_get_access_protos(rec, &protos) == 0)
- ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ cdata = rfcomm_conn_cont_data_new(conn, msg, dst, string, dbus_data);
+ if (!cdata)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
- if (ch == -1)
- return error_record_does_not_exist(conn, msg);
+ if ((uuid = str2uuid128(string))) {
+ if ((err = get_record_with_uuid(conn, msg, dbus_data->dev_id,
+ dst, uuid,
+ rfcomm_conn_req_continue,
+ cdata)) < 0)
+ goto failed;
+ } else if ((handle = str2handle(string))) {
+ if ((err = get_record_with_handle(conn, msg, dbus_data->dev_id,
+ dst, handle,
+ rfcomm_conn_req_continue,
+ cdata)) < 0)
+ goto failed;
+ } else {
+ rfcomm_conn_cont_data_free(cdata);
+ return error_invalid_arguments(conn, msg);
+ }
- if (find_pending_connect(dst, ch))
- return error_connect_in_progress(conn, msg);
-
- if (rfcomm_connect(conn, msg, &bdaddr, dst, NULL, ch, &err) < 0)
- return error_failed(conn, msg, err);
-
return DBUS_HANDLER_RESULT_HANDLED;
+
+failed:
+ if (uuid)
+ free(uuid);
+ if (handle)
+ free(handle);
+ rfcomm_conn_cont_data_free(cdata);
+ return error_failed(conn, msg, err);
}
static DBusHandlerResult rfcomm_cancel_connect_req(DBusConnection *conn,
- DBusMessage *msg, void *data)
+ DBusMessage *msg,
+ void *data)
{
- int ch = -1;
- const char *dst;
- const char *string;
- sdp_record_t *rec;
- sdp_list_t *protos;
- bdaddr_t bdaddr;
- struct hci_dbus_data *dbus_data = data;
- DBusMessage *reply;
struct pending_connect *pending;
+ DBusMessage *reply;
+ const char *string;
+ const char *dst;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &dst,
- DBUS_TYPE_STRING, &string,
- DBUS_TYPE_INVALID))
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_STRING, &string,
+ DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- hci_devba(dbus_data->dev_id, &bdaddr);
-
- rec = get_record_from_string(dst, string);
-
- if (!rec)
- return error_record_does_not_exist(conn, msg);
-
- if (sdp_get_access_protos(rec, &protos) == 0)
- ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-
- if (ch == -1)
- return error_record_does_not_exist(conn, msg);
+ pending = find_pending_connect_by_service(dst, string);
+ if (!pending)
+ return error_connect_not_in_progress(conn, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- pending = find_pending_connect(dst, ch);
- if (!pending)
- return error_connect_not_in_progress(conn, msg);
-
pending->canceled = 1;
-
+
return send_reply_and_unref(conn, reply);
}
@@ -663,7 +769,7 @@ static DBusHandlerResult rfcomm_connect_by_ch_req(DBusConnection *conn,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- if (find_pending_connect(dst, ch))
+ if (find_pending_connect_by_channel(dst, ch))
return error_connect_in_progress(conn, msg);
if (rfcomm_connect(conn, msg, &bdaddr, dst, NULL, ch, &err) < 0)
@@ -686,7 +792,7 @@ static DBusHandlerResult rfcomm_cancel_connect_by_ch_req(DBusConnection *conn,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- pending = find_pending_connect(dst, ch);
+ pending = find_pending_connect_by_channel(dst, ch);
if (!pending)
return error_connect_not_in_progress(conn, msg);
@@ -737,7 +843,7 @@ static DBusHandlerResult rfcomm_disconnect_req(DBusConnection *conn,
}
static DBusHandlerResult rfcomm_bind_req(DBusConnection *conn,
- DBusMessage *msg, void *data)
+ DBusMessage *msg, void *data)
{
error("RFCOMM.Bind not implemented");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c
index 8c6f3453..7002350a 100644
--- a/hcid/dbus-sdp.c
+++ b/hcid/dbus-sdp.c
@@ -67,16 +67,22 @@ struct transaction_context {
DBusConnection *conn;
DBusMessage *rq;
sdp_session_t *session;
-};
+ /* Used for internal async get remote service record implementation */
+ void *priv;
+};
-typedef int connect_cb_t (struct transaction_context *t);
+typedef int connect_cb_t(struct transaction_context *t);
struct pending_connect {
DBusConnection *conn;
DBusMessage *rq;
- sdp_session_t *session;
+
char *dst;
+ sdp_session_t *session;
connect_cb_t *conn_cb;
+
+ /* Used for internal async get remote service record implementation */
+ void *priv;
};
/* FIXME: move to a common file */
@@ -161,13 +167,16 @@ static struct pending_connect *pending_connect_new(DBusConnection *conn, DBusMes
return NULL;
c = malloc(sizeof(*c));
-
+ if (!c)
+ return NULL;
memset(c, 0, sizeof(*c));
if (dst) {
c->dst = strdup(dst);
- if (!c->dst)
- goto fail;
+ if (!c->dst) {
+ free(c);
+ return NULL;
+ }
}
c->conn = dbus_connection_ref(conn);
@@ -175,13 +184,6 @@ static struct pending_connect *pending_connect_new(DBusConnection *conn, DBusMes
c->conn_cb = cb;
return c;
-
-fail:
- if (c->dst)
- free(c->dst);
- free(c);
-
- return NULL;
}
static void pending_connect_free(struct pending_connect *c)
@@ -400,6 +402,69 @@ static int sdp_cache_append(const char *owner, const char *prov, sdp_record_t *r
return 0;
}
+static void transaction_context_free(void *udata)
+{
+ struct transaction_context *ctxt = udata;
+
+ if (!ctxt)
+ return;
+
+ if (ctxt->conn)
+ dbus_connection_unref(ctxt->conn);
+
+ if (ctxt->rq)
+ dbus_message_unref(ctxt->rq);
+
+ if (ctxt->session)
+ sdp_close(ctxt->session);
+
+ free(ctxt);
+}
+
+typedef struct {
+ uint16_t dev_id;
+ char *dst;
+ void *search_data;
+ get_record_cb_t *cb;
+ void *data;
+} get_record_data_t;
+
+static get_record_data_t *get_record_data_new(uint16_t dev_id, const char *dst,
+ void *search_data,
+ get_record_cb_t *cb, void *data)
+{
+ get_record_data_t *n;
+
+ n = malloc(sizeof(*n));
+ if (!n)
+ return NULL;
+
+ n->dst = strdup(dst);
+ if (!n->dst) {
+ free(n);
+ return NULL;
+ }
+
+ n->dev_id = dev_id;
+ n->search_data = search_data;
+ n->cb = cb;
+ n->data = data;
+
+ return n;
+}
+
+static void get_record_data_free(get_record_data_t *d)
+{
+ free(d->dst);
+ free(d);
+}
+
+static inline void get_record_data_call_cb(get_record_data_t *d,
+ sdp_record_t *rec, int err)
+{
+ d->cb(rec, d->data, err);
+}
+
static void owner_exited(const char *owner, struct hci_dbus_data *dbus_data)
{
struct slist *lp, *next, *lr;
@@ -412,7 +477,7 @@ static void owner_exited(const char *owner, struct hci_dbus_data *dbus_data)
next = lp->next;
p = lp->data;
-
+
if (!p->owner || strcmp(p->owner, owner))
continue;
@@ -437,7 +502,8 @@ static void owner_exited(const char *owner, struct hci_dbus_data *dbus_data)
}
}
-static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond, void *udata)
+static gboolean search_process_cb(GIOChannel *chan,
+ GIOCondition cond, void *udata)
{
struct transaction_context *ctxt = udata;
int sk, err = 0;
@@ -446,22 +512,27 @@ static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond, void *uda
sk = g_io_channel_unix_get_fd(chan);
len = sizeof(err);
-
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
error("getsockopt(): %s (%d)", strerror(errno), errno);
- error_failed(ctxt->conn, ctxt->rq, errno);
- goto fail;
+ err = errno;
+ goto failed;
}
-
if (err != 0) {
- error_failed(ctxt->conn, ctxt->rq, err);
error("sock error: %s (%d)", strerror(err), err);
- goto fail;
+ goto failed;
}
+
if (!sdp_process(ctxt->session))
return TRUE;
-fail:
+failed:
+ if (err) {
+ if (ctxt->priv) {
+ get_record_data_call_cb(ctxt->priv, NULL, err);
+ get_record_data_free(ctxt->priv);
+ } else
+ error_failed(ctxt->conn, ctxt->rq, err);
+ }
g_io_channel_unref(chan);
return FALSE;
}
@@ -687,75 +758,62 @@ done:
send_reply_and_unref(ctxt->conn, reply);
}
-static void transaction_context_free(void *udata)
-{
- struct transaction_context *ctxt = udata;
-
- if (!ctxt)
- return;
-
- if (ctxt->conn)
- dbus_connection_unref(ctxt->conn);
-
- if (ctxt->rq)
- dbus_message_unref(ctxt->rq);
-
- if (ctxt->session)
- sdp_close(ctxt->session);
-
- free(ctxt);
-}
-
-static gboolean sdp_client_connect_cb(GIOChannel *chan, GIOCondition cond, void *udata)
+static gboolean sdp_client_connect_cb(GIOChannel *chan,
+ GIOCondition cond, void *udata)
{
struct pending_connect *c = udata;
struct transaction_context *ctxt = NULL;
- int sdp_err, err = 0, sk = 0;
+ int sdp_err, err = 0, sk;
socklen_t len;
sk = g_io_channel_unix_get_fd(chan);
len = sizeof(err);
-
if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
error("getsockopt(): %s (%d)", strerror(errno), errno);
err = errno;
- goto fail;
+ goto failed;
}
-
if (err != 0) {
error("connect(): %s (%d)", strerror(err), err);
- goto fail;
+ goto failed;
}
ctxt = malloc(sizeof(*ctxt));
if (!ctxt) {
err = ENOMEM;
- goto fail;
+ goto failed;
}
-
memset(ctxt, 0, sizeof(*ctxt));
ctxt->conn = dbus_connection_ref(c->conn);
ctxt->rq = dbus_message_ref(c->rq);
ctxt->session = c->session;
+ if (c->priv)
+ ctxt->priv = c->priv;
- /* set the complete transaction callback and starts the search request */
+ /* set the complete transaction callback and send the search request */
sdp_err = c->conn_cb(ctxt);
if (sdp_err < 0) {
err = -sdp_err;
error("search failed: %s (%d)", strerror(err), err);
- goto fail;
+ goto failed;
}
/* set the callback responsible for update the transaction data */
- g_io_add_watch_full(chan, 0, G_IO_IN, search_process_cb,
- ctxt, transaction_context_free);
+ g_io_add_watch_full(chan, 0, G_IO_IN,
+ search_process_cb, ctxt, transaction_context_free);
goto done;
-fail:
- if (err)
- error_connection_attempt_failed(c->conn, c->rq, err);
+failed:
+ if (err) {
+ if (c->priv)
+ get_record_data_call_cb(c->priv, NULL, err);
+ else
+ error_connection_attempt_failed(c->conn, c->rq, err);
+ }
+ if (c->priv)
+ get_record_data_free(c->priv);
if (ctxt)
transaction_context_free(ctxt);
g_io_channel_unref(chan);
@@ -766,19 +824,21 @@ done:
return FALSE;
}
-static int connect_request(DBusConnection *conn, DBusMessage *msg,
- uint16_t dev_id, const char *dst,
- connect_cb_t *cb, int *err)
+static struct pending_connect *connect_request(DBusConnection *conn,
+ DBusMessage *msg,
+ uint16_t dev_id,
+ const char *dst,
+ connect_cb_t *cb, int *err)
{
- struct pending_connect *c = NULL;
- GIOChannel *chan = NULL;
+ struct pending_connect *c;
bdaddr_t srcba, dstba;
+ GIOChannel *chan;
c = pending_connect_new(conn, msg, dst, cb);
if (!c) {
if (err)
*err = ENOMEM;
- return -1;
+ return NULL;
}
hci_devba(dev_id, &srcba);
@@ -790,7 +850,7 @@ static int connect_request(DBusConnection *conn, DBusMessage *msg,
*err = errno;
error("sdp_connect() failed: %s (%d)", strerror(errno), errno);
pending_connect_free(c);
- return -1;
+ return NULL;
}
chan = g_io_channel_unix_new(sdp_get_socket(c->session));
@@ -799,7 +859,7 @@ static int connect_request(DBusConnection *conn, DBusMessage *msg,
g_io_add_watch(chan, G_IO_OUT, sdp_client_connect_cb, c);
pending_connects = slist_append(pending_connects, c);
- return 0;
+ return c;
}
static int remote_svc_rec_conn_cb(struct transaction_context *ctxt)
@@ -850,7 +910,8 @@ DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, voi
if (find_pending_connect(dst))
return error_service_search_in_progress(conn, msg);
- if (connect_request(conn, msg, dbus_data->dev_id, dst, remote_svc_rec_conn_cb, &err) < 0) {
+ if (!connect_request(conn, msg, dbus_data->dev_id,
+ dst, remote_svc_rec_conn_cb, &err)) {
error("Search request failed: %s (%d)", strerror(err), err);
return error_failed(conn, msg, err);
}
@@ -900,7 +961,8 @@ DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg,
if (find_pending_connect(dst))
return error_service_search_in_progress(conn, msg);
- if (connect_request(conn, msg, dbus_data->dev_id, dst, remote_svc_handles_conn_cb, &err) < 0) {
+ if (!connect_request(conn, msg, dbus_data->dev_id,
+ dst, remote_svc_handles_conn_cb, &err)) {
error("Search request failed: %s (%d)", strerror(err), err);
return error_failed(conn, msg, err);
}
@@ -951,7 +1013,8 @@ static DBusHandlerResult get_identifiers(DBusConnection *conn,
if (find_pending_connect(dst))
return error_service_search_in_progress(conn, msg);
- if (connect_request(conn, msg, dbus_data->dev_id, dst, get_identifiers_conn_cb, &err) < 0) {
+ if (!connect_request(conn, msg, dbus_data->dev_id,
+ dst, get_identifiers_conn_cb, &err)) {
error("Search request failed: %s (%d)", strerror(err), err);
return error_failed(conn, msg, err);
}
@@ -1075,8 +1138,8 @@ search_request:
if (find_pending_connect(dst))
return error_service_search_in_progress(conn, msg);
- if (connect_request(conn, msg, dbus_data->dev_id, dst,
- get_identifiers_by_service_conn_cb, &err) < 0) {
+ if (!connect_request(conn, msg, dbus_data->dev_id,
+ dst, get_identifiers_by_service_conn_cb, &err)) {
error("Search request failed: %s (%d)", strerror(err), err);
return error_failed(conn, msg, err);
}
@@ -1093,7 +1156,7 @@ static int uuid_cmp(const void *key1, const void *key2)
/* converting to uuid128 */
a = sdp_uuid_to_uuid128((uuid_t *) key1);
b = sdp_uuid_to_uuid128((uuid_t *) key2);
-
+
ret_val = sdp_uuid128_cmp(a, b);
bt_free(a);
@@ -1102,7 +1165,7 @@ static int uuid_cmp(const void *key1, const void *key2)
return ret_val;
}
-sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid)
+static sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid)
{
struct slist *lp, *lr;
struct service_provider *p;
@@ -1119,16 +1182,17 @@ sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid)
/* Check whether the record has the correct uuid */
if (sdp_get_service_classes(r->record, &list) != 0)
continue;
-
+
if (sdp_list_find(list, uuid, uuid_cmp))
return r->record;
}
}
return NULL;
-}
+}
-sdp_record_t *find_record_by_handle(const char *address, uint32_t handle)
+static sdp_record_t *find_record_by_handle(const char *address,
+ uint32_t handle)
{
struct slist *lp, *lr;
struct service_provider *p;
@@ -1406,3 +1470,227 @@ void dbus_sdp_cache_free()
{
slist_foreach(sdp_cache, service_provider_free, NULL);
}
+
+/*
+ * Internal async get remote service record implementation
+ */
+
+static void get_rec_with_handle_comp_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ int scanned, cb_err = 0;
+ sdp_record_t *rec = NULL;
+
+ if (err == 0xffff) {
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ cb_err = EINVAL;
+ goto failed;
+ }
+ error("search failed :%s (%d)", strerror(sdp_err), sdp_err);
+ cb_err = sdp_err;
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP || type != SDP_SVC_ATTR_RSP) {
+ error("SDP error: %s(%d)", strerror(EPROTO), EPROTO);
+ cb_err = EPROTO;
+ goto failed;
+ }
+
+ rec = sdp_extract_pdu(rsp, &scanned);
+ if (!rec) {
+ error("Service record is NULL");
+ cb_err = EPROTO;
+ goto failed;
+ }
+
+ /* FIXME: add record to the cache! */
+
+failed:
+ get_record_data_call_cb(ctxt->priv, rec, cb_err);
+ get_record_data_free(ctxt->priv);
+}
+
+static int get_rec_with_handle_conn_cb(struct transaction_context *ctxt)
+{
+ get_record_data_t *d = ctxt->priv;
+ uint32_t range = 0x0000ffff;
+ sdp_list_t *attrids = NULL;
+ uint32_t handle;
+ int err = 0;
+
+ if (sdp_set_notify(ctxt->session,
+ get_rec_with_handle_comp_cb, ctxt) < 0) {
+ error("Invalid session data!");
+ err = -EINVAL;
+ goto failed;
+ }
+
+ handle = *((uint32_t *)d->search_data);
+ attrids = sdp_list_append(NULL, &range);
+
+ if (sdp_service_attr_async(ctxt->session, handle,
+ SDP_ATTR_REQ_RANGE, attrids) < 0) {
+ error("send request failed: %s (%d)", strerror(errno), errno);
+ err = -errno;
+ goto failed;
+ }
+
+failed:
+ free(d->search_data);
+ if (attrids)
+ sdp_list_free(attrids, NULL);
+
+ return err;
+}
+
+int get_record_with_handle(DBusConnection *conn, DBusMessage *msg,
+ uint16_t dev_id, const char *dst,
+ uint32_t *handle, get_record_cb_t *cb, void *data)
+{
+ struct pending_connect *c;
+ get_record_data_t *d;
+ int err;
+
+ /* FIXME: search the cache first! */
+
+ if (find_pending_connect(dst)) {
+ error("SDP search in progress!");
+ return -EINPROGRESS;
+ }
+
+ d = get_record_data_new(dev_id, dst, handle, cb, data);
+ if (!d)
+ return -ENOMEM;
+
+ if (!(c = connect_request(conn, msg, dev_id, dst,
+ get_rec_with_handle_conn_cb, &err))) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ get_record_data_free(d);
+ return -err;
+ }
+
+ c->priv = d;
+
+ return 0;
+}
+
+static void get_rec_with_uuid_comp_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ get_record_data_t *d = ctxt->priv;
+ int csrc, tsrc, cb_err = 0;
+ sdp_record_t *rec = NULL;
+ uint32_t *handle;
+ uint8_t *pdata;
+
+ if (err == 0xffff) {
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ cb_err = EINVAL;
+ goto failed;
+ }
+ error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+ cb_err = sdp_err;
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP || type != SDP_SVC_SEARCH_RSP) {
+ error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+ cb_err = EPROTO;
+ goto failed;
+ }
+
+ pdata = rsp;
+ tsrc = ntohs(bt_get_unaligned((uint16_t *) pdata));
+ if (tsrc <= 0)
+ goto failed;
+ pdata += sizeof(uint16_t);
+
+ csrc = ntohs(bt_get_unaligned((uint16_t *) pdata));
+ if (csrc <= 0)
+ goto failed;
+ pdata += sizeof(uint16_t);
+
+ /* FIXME: what should we do with the other handles?? */
+ handle = malloc(sizeof(*handle));
+ if (!handle) {
+ cb_err = ENOMEM;
+ goto failed;
+ }
+
+ *handle = ntohl(bt_get_unaligned((uint32_t*)pdata));
+ get_record_with_handle(ctxt->conn, ctxt->rq, d->dev_id,
+ d->dst, handle, d->cb, d->data);
+ get_record_data_free(ctxt->priv);
+ return;
+
+failed:
+ get_record_data_call_cb(ctxt->priv, rec, cb_err);
+ get_record_data_free(ctxt->priv);
+}
+
+static int get_rec_with_uuid_conn_cb(struct transaction_context *ctxt)
+{
+ get_record_data_t *d = ctxt->priv;
+ sdp_list_t *search = NULL;
+ uuid_t *uuid;
+ int err = 0;
+
+ if (sdp_set_notify(ctxt->session,
+ get_rec_with_uuid_comp_cb, ctxt) < 0) {
+ err = -EINVAL;
+ goto failed;
+ }
+
+ uuid = (uuid_t *)d->search_data;
+ search = sdp_list_append(NULL, uuid);
+
+ if (sdp_service_search_async(ctxt->session, search, 64) < 0) {
+ error("send request failed: %s (%d)", strerror(errno), errno);
+ err = -sdp_get_error(ctxt->session);
+ }
+
+failed:
+ free(d->search_data);
+ if (search)
+ sdp_list_free(search, NULL);
+
+ return err;
+}
+
+int get_record_with_uuid(DBusConnection *conn, DBusMessage *msg,
+ uint16_t dev_id, const char *dst,
+ uuid_t *uuid, get_record_cb_t *cb, void *data)
+{
+ struct pending_connect *c;
+ get_record_data_t *d;
+ int err;
+
+ /* FIXME: search the cache first! */
+
+ if (find_pending_connect(dst)) {
+ error("SDP search in progress!");
+ return -EINPROGRESS;
+ }
+
+ d = get_record_data_new(dev_id, dst, uuid, cb, data);
+ if (!d)
+ return -ENOMEM;
+
+ if (!(c = connect_request(conn, msg, dev_id, dst,
+ get_rec_with_uuid_conn_cb, &err))) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ get_record_data_free(d);
+ return -err;
+ }
+
+ c->priv = d;
+
+ return 0;
+}
diff --git a/hcid/dbus.h b/hcid/dbus.h
index 02ebf6b1..3dc5bd59 100644
--- a/hcid/dbus.h
+++ b/hcid/dbus.h
@@ -238,8 +238,13 @@ int disc_device_req_name(struct hci_dbus_data *dbus_data);
int discoverable_timeout_handler(void *data);
-sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid);
-sdp_record_t *find_record_by_handle(const char *address, uint32_t handle);
uint16_t sdp_str2svclass(const char *str);
+typedef void get_record_cb_t(sdp_record_t *rec, void *data, int err);
+int get_record_with_uuid(DBusConnection *conn, DBusMessage *msg,
+ uint16_t dev_id, const char *dst,
+ uuid_t *uuid, get_record_cb_t *cb, void *data);
+int get_record_with_handle(DBusConnection *conn, DBusMessage *msg,
+ uint16_t dev_id, const char *dst,
+ uint32_t *handle, get_record_cb_t *cb, void *data);
#endif /* __H_BLUEZ_DBUS_H__ */