summaryrefslogtreecommitdiffstats
path: root/hcid/dbus-rfcomm.c
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 /hcid/dbus-rfcomm.c
parent265dbd3308253a1f94fe43c27c1d65f0059df77a (diff)
Make RFCOMM.Connect() do an SDP search before connecting
Diffstat (limited to 'hcid/dbus-rfcomm.c')
-rw-r--r--hcid/dbus-rfcomm.c298
1 files changed, 202 insertions, 96 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;