static DBusMessage *characteristic_read_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct characteristic *chrc = user_data; struct bt_gatt_client *gatt = chrc->service->client->gatt; struct async_dbus_op *op; if (chrc->read_id) return btd_error_in_progress(msg); op = new0(struct async_dbus_op, 1); if (!op) return btd_error_failed(msg, "Failed to initialize request"); op->msg = dbus_message_ref(msg); op->data = chrc; chrc->read_id = bt_gatt_client_read_value(gatt, chrc->value_handle, chrc_read_cb, async_dbus_op_ref(op), async_dbus_op_unref); if (chrc->read_id) return NULL; async_dbus_op_free(op); return btd_error_failed(msg, "Failed to send read request"); }
static unsigned int start_write_request(DBusMessage *msg, uint16_t handle, struct bt_gatt_client *gatt, const uint8_t *value, size_t value_len, void *data, async_dbus_op_complete_t complete) { struct async_dbus_op *op; unsigned int id; op = new0(struct async_dbus_op, 1); if (!op) return false; op->msg = dbus_message_ref(msg); op->data = data; op->complete = complete; id = bt_gatt_client_write_value(gatt, handle, value, value_len, write_cb, op, async_dbus_op_free); if (!id) async_dbus_op_free(op); return id; }
static DBusMessage *descriptor_read_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct descriptor *desc = user_data; struct bt_gatt_client *gatt = desc->chrc->service->client->gatt; struct async_dbus_op *op; if (!gatt) return btd_error_failed(msg, "Not connected"); if (desc->read_id) return btd_error_in_progress(msg); op = new0(struct async_dbus_op, 1); op->msg = dbus_message_ref(msg); op->data = desc; desc->read_id = bt_gatt_client_read_value(gatt, desc->handle, desc_read_cb, async_dbus_op_ref(op), async_dbus_op_unref); if (desc->read_id) return NULL; async_dbus_op_free(op); return btd_error_failed(msg, "Failed to send read request"); }
static void register_notify(void *data, void *user_data) { struct notify_client *notify_client = data; struct btd_gatt_client *client = user_data; struct async_dbus_op *op; DBG("Re-register subscribed notification client"); op = new0(struct async_dbus_op, 1); op->data = notify_client; notify_client->notify_id = bt_gatt_client_register_notify(client->gatt, notify_client->chrc->value_handle, register_notify_cb, notify_cb, op, async_dbus_op_free); if (notify_client->notify_id) return; async_dbus_op_free(op); DBG("Failed to re-register notification client"); queue_remove(notify_client->chrc->notify_clients, client); queue_remove(client->all_notify_clients, client); notify_client_free(notify_client); }
static void async_dbus_op_unref(void *data) { struct async_dbus_op *op = data; if (__sync_sub_and_fetch(&op->ref_count, 1)) return; async_dbus_op_free(op); }
static DBusMessage *characteristic_start_notify(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct characteristic *chrc = user_data; struct bt_gatt_client *gatt = chrc->service->client->gatt; const char *sender = dbus_message_get_sender(msg); struct async_dbus_op *op; struct notify_client *client; if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY || chrc->props & BT_GATT_CHRC_PROP_INDICATE)) return btd_error_not_supported(msg); /* Each client can only have one active notify session. */ client = queue_find(chrc->notify_clients, match_notify_sender, sender); if (client) return client->notify_id ? btd_error_failed(msg, "Already notifying") : btd_error_in_progress(msg); client = notify_client_create(chrc, sender); if (!client) return btd_error_failed(msg, "Failed allocate notify session"); queue_push_tail(chrc->notify_clients, client); queue_push_tail(chrc->service->client->all_notify_clients, client); /* * If the device is currently not connected, return success. We will * automatically try and register all clients when a GATT client becomes * ready. */ if (!gatt) { DBusMessage *reply; reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); if (reply) return reply; /* * Clean up and respond with an error instead of timing out to * avoid any ambiguities. */ error("Failed to construct D-Bus message reply"); goto fail; } op = new0(struct async_dbus_op, 1); op->data = client; op->msg = dbus_message_ref(msg); client->notify_id = bt_gatt_client_register_notify(gatt, chrc->value_handle, register_notify_cb, notify_cb, op, async_dbus_op_free); if (client->notify_id) return NULL; async_dbus_op_free(op); fail: queue_remove(chrc->notify_clients, client); queue_remove(chrc->service->client->all_notify_clients, client); /* Directly free the client */ notify_client_free(client); return btd_error_failed(msg, "Failed to register notify session"); }