diff --git a/src/gatt-database.c b/src/gatt-database.c
index 7594ee3..a68bb4f 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
GDBusProxy *proxy;
struct gatt_db_attribute *attrib;
bool handled;
+ struct queue *pending_reads;
+ struct queue *pending_writes;
};
struct pending_op {
- struct external_chrc *chrc;
unsigned int id;
- void *user_data;
+ struct gatt_db_attribute *attrib;
+ struct queue *owner_queue;
+ void *setup_data;
};
struct device_state {
{
struct pending_op *op = data;
- gatt_db_attribute_read_result(op->chrc->attrib, op->id,
+ gatt_db_attribute_read_result(op->attrib, op->id,
BT_ATT_ERROR_REQUEST_NOT_SUPPORTED,
NULL, 0);
+ op->owner_queue = NULL;
}
static void cancel_pending_write(void *data)
{
struct pending_op *op = data;
- gatt_db_attribute_write_result(op->chrc->attrib, op->id,
+ gatt_db_attribute_write_result(op->attrib, op->id,
BT_ATT_ERROR_REQUEST_NOT_SUPPORTED);
+ op->owner_queue = NULL;
}
static void chrc_free(void *data)
{
struct external_desc *desc = data;
+ queue_destroy(desc->pending_reads, cancel_pending_read);
+ queue_destroy(desc->pending_writes, cancel_pending_write);
+
g_dbus_proxy_unref(desc->proxy);
g_free(desc->chrc_path);
if (!desc)
return NULL;
+ desc->pending_reads = queue_new();
+ if (!desc->pending_reads) {
+ free(desc);
+ return NULL;
+ }
+
+ desc->pending_writes = queue_new();
+ if (!desc->pending_writes) {
+ queue_destroy(desc->pending_reads, NULL);
+ free(desc);
+ return NULL;
+ }
+
desc->chrc_path = g_strdup(chrc_path);
if (!desc->chrc_path) {
+ queue_destroy(desc->pending_reads, NULL);
+ queue_destroy(desc->pending_writes, NULL);
free(desc);
return NULL;
}
uint8_t *value = NULL;
int len = 0;
- if (!op->chrc) {
+ if (!op->owner_queue) {
DBG("Pending read was canceled when object got removed");
return;
}
value = len ? value : NULL;
done:
- gatt_db_attribute_read_result(op->chrc->attrib, op->id, ecode,
- value, len);
+ gatt_db_attribute_read_result(op->attrib, op->id, ecode, value, len);
}
-static struct pending_op *pending_read_new(struct external_chrc *chrc,
- unsigned int id)
+static void pending_op_free(void *data)
+{
+ struct pending_op *op = data;
+
+ if (op->owner_queue)
+ queue_remove(op->owner_queue, op);
+
+ free(op);
+}
+
+static struct pending_op *pending_read_new(struct queue *owner_queue,
+ struct gatt_db_attribute *attrib,
+ unsigned int id)
{
struct pending_op *op;
if (!op)
return NULL;
- op->chrc = chrc;
+ op->owner_queue = owner_queue;
+ op->attrib = attrib;
op->id = id;
- queue_push_tail(chrc->pending_reads, op);
+ queue_push_tail(owner_queue, op);
return op;
}
-static void pending_read_free(void *data)
-{
- struct pending_op *op = data;
-
- if (op->chrc)
- queue_remove(op->chrc->pending_reads, op);
-
- free(op);
-}
-
-static void chrc_read_cb(struct gatt_db_attribute *attrib,
- unsigned int id, uint16_t offset,
- uint8_t opcode, struct bt_att *att,
- void *user_data)
+static void send_read(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
+ struct queue *owner_queue,
+ unsigned int id)
{
- struct external_chrc *chrc = user_data;
struct pending_op *op;
uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
- if (chrc->attrib != attrib) {
- error("Read callback called with incorrect attribute");
- goto error;
-
- }
-
- op = pending_read_new(chrc, id);
+ op = pending_read_new(owner_queue, attrib, id);
if (!op) {
error("Failed to allocate memory for pending read call");
ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
goto error;
}
- if (g_dbus_proxy_method_call(chrc->proxy, "ReadValue", NULL,
- read_reply_cb, op,
- pending_read_free) == TRUE)
+ if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply_cb,
+ op, pending_op_free) == TRUE)
return;
- pending_read_free(op);
+ pending_op_free(op);
error:
gatt_db_attribute_read_result(attrib, id, ecode, NULL, 0);
static void write_setup_cb(DBusMessageIter *iter, void *user_data)
{
struct pending_op *op = user_data;
- struct iovec *iov = op->user_data;
+ struct iovec *iov = op->setup_data;
DBusMessageIter array;
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
DBusMessageIter iter;
uint8_t ecode = 0;
- if (!op->chrc) {
+ if (!op->owner_queue) {
DBG("Pending write was canceled when object got removed");
return;
}
}
done:
- gatt_db_attribute_write_result(op->chrc->attrib, op->id, ecode);
+ gatt_db_attribute_write_result(op->attrib, op->id, ecode);
}
-static struct pending_op *pending_write_new(struct external_chrc *chrc,
- unsigned int id,
- const uint8_t *value,
- size_t len)
+static struct pending_op *pending_write_new(struct queue *owner_queue,
+ struct gatt_db_attribute *attrib,
+ unsigned int id,
+ const uint8_t *value,
+ size_t len)
{
struct pending_op *op;
struct iovec iov;
iov.iov_base = (uint8_t *) value;
iov.iov_len = len;
- op->chrc = chrc;
+ op->owner_queue = owner_queue;
+ op->attrib = attrib;
op->id = id;
- op->user_data = &iov;
- queue_push_tail(chrc->pending_writes, op);
+ op->setup_data = &iov;
+ queue_push_tail(owner_queue, op);
return op;
}
-static void pending_write_free(void *data)
-{
- struct pending_op *op = data;
-
- if (op->chrc)
- queue_remove(op->chrc->pending_writes, op);
-
- free(op);
-}
-
-static void chrc_write_cb(struct gatt_db_attribute *attrib,
- unsigned int id, uint16_t offset,
- const uint8_t *value, size_t len,
- uint8_t opcode, struct bt_att *att,
- void *user_data)
+static void send_write(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
+ struct queue *owner_queue,
+ unsigned int id,
+ const uint8_t *value, size_t len)
{
- struct external_chrc *chrc = user_data;
struct pending_op *op;
uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
- if (chrc->attrib != attrib) {
- error("Write callback called with incorrect attribute");
- goto error;
- }
-
- op = pending_write_new(chrc, id, value, len);
+ op = pending_write_new(owner_queue, attrib, id, value, len);
if (!op) {
error("Failed to allocate memory for pending read call");
ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
goto error;
}
- if (g_dbus_proxy_method_call(chrc->proxy, "WriteValue", write_setup_cb,
+ if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb,
write_reply_cb, op,
- pending_write_free) == TRUE)
+ pending_op_free) == TRUE)
return;
- pending_write_free(op);
+ pending_op_free(op);
error:
gatt_db_attribute_write_result(attrib, id, ecode);
return true;
}
+static void desc_read_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct external_desc *desc = user_data;
+
+ if (desc->attrib != attrib) {
+ error("Read callback called with incorrect attribute");
+ return;
+ }
+
+ send_read(attrib, desc->proxy, desc->pending_reads, id);
+}
+
+static void desc_write_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct external_desc *desc = user_data;
+
+ if (desc->attrib != attrib) {
+ error("Read callback called with incorrect attribute");
+ return;
+ }
+
+ send_write(attrib, desc->proxy, desc->pending_writes, id, value, len);
+}
+
static bool database_add_desc(struct external_service *service,
struct external_desc *desc)
{
}
/*
- * TODO: Set read/write callbacks and property set permissions based on
- * a D-Bus property of the external descriptor.
+ * TODO: Set permissions based on a D-Bus property of the external
+ * descriptor.
*/
- desc->attrib = gatt_db_service_add_descriptor(service->attrib,
- &uuid, 0, NULL,
- NULL, NULL);
-
+ desc->attrib = gatt_db_service_add_descriptor(service->attrib, &uuid,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ desc_read_cb, desc_write_cb, desc);
if (!desc->attrib) {
error("Failed to create descriptor entry in database");
return false;
return true;
}
+static void chrc_read_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct external_chrc *chrc = user_data;
+
+ if (chrc->attrib != attrib) {
+ error("Read callback called with incorrect attribute");
+ return;
+ }
+
+ send_read(attrib, chrc->proxy, chrc->pending_reads, id);
+}
+
+static void chrc_write_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct external_chrc *chrc = user_data;
+
+ if (chrc->attrib != attrib) {
+ error("Write callback called with incorrect attribute");
+ return;
+ }
+
+ send_write(attrib, chrc->proxy, chrc->pending_writes, id, value, len);
+}
+
static bool database_add_chrc(struct external_service *service,
struct external_chrc *chrc)
{