summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2023-07-24 13:57:34 -0700
committerWootak Jung <wootak.jung@samsung.com>2024-04-01 11:29:18 +0900
commit7852ea12fca6ea8194c438a98c0d3cbda54e4290 (patch)
tree04901413a95b7bb07344f640a02e82a5bb78b381
parent10201b1a0633e802bacc0f749a30b1ee21448051 (diff)
downloadbluez-7852ea12fca6ea8194c438a98c0d3cbda54e4290.tar.gz
bluez-7852ea12fca6ea8194c438a98c0d3cbda54e4290.tar.bz2
bluez-7852ea12fca6ea8194c438a98c0d3cbda54e4290.zip
gatt: Fix not establishing a socket for each deviceaccepted/tizen/7.0/unified/20240401.145447
AcquireWrite and AcquireNotify shall establish a socket pair for each device connected otherwise the application cannot distinct the operations of each client. Fixes: https://github.com/bluez/bluez/issues/460 Change-Id: I41e63c8ac8164205c43612670ed1cd5d0d09e147
-rw-r--r--src/gatt-database.c159
1 files changed, 137 insertions, 22 deletions
diff --git a/src/gatt-database.c b/src/gatt-database.c
index cbf964f8..8a75831c 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -108,6 +108,12 @@ struct external_profile {
struct queue *profiles; /* btd_profile list */
};
+struct client_io {
+ struct bt_att *att;
+ unsigned int disconn_id;
+ struct io *io;
+};
+
struct external_chrc {
struct external_service *service;
char *path;
@@ -117,8 +123,8 @@ struct external_chrc {
uint32_t perm;
uint32_t ccc_perm;
uint16_t mtu;
- struct io *write_io;
- struct io *notify_io;
+ struct queue *write_ios;
+ struct queue *notify_ios;
struct gatt_db_attribute *attrib;
struct gatt_db_attribute *ccc;
struct queue *pending_reads;
@@ -517,12 +523,22 @@ static void cancel_pending_write(void *data)
op->owner_queue = NULL;
}
+static void client_io_free(void *data)
+{
+ struct client_io *client = data;
+
+ bt_att_unregister_disconnect(client->att, client->disconn_id);
+ bt_att_unref(client->att);
+ io_destroy(client->io);
+ free(client);
+}
+
static void chrc_free(void *data)
{
struct external_chrc *chrc = data;
- io_destroy(chrc->write_io);
- io_destroy(chrc->notify_io);
+ queue_destroy(chrc->write_ios, client_io_free);
+ queue_destroy(chrc->notify_ios, client_io_free);
queue_destroy(chrc->pending_reads, cancel_pending_read);
queue_destroy(chrc->pending_writes, cancel_pending_write);
@@ -2971,18 +2987,29 @@ static void flush_pending_writes(GDBusProxy *proxy,
queue_remove_all(owner_queue, NULL, NULL, NULL);
}
+static bool match_client_io(const void *data, const void *user_data)
+{
+ const struct client_io *client = data;
+ const struct io *io = user_data;
+
+ return client->io == io;
+}
+
static bool sock_hup(struct io *io, void *user_data)
{
struct external_chrc *chrc = user_data;
+ struct client_io *client;
DBG("%p closed\n", io);
- if (io == chrc->write_io)
- chrc->write_io = NULL;
- else
- chrc->notify_io = NULL;
+ client = queue_remove_if(chrc->write_ios, match_client_io, io);
+ if (!client) {
+ client = queue_remove_if(chrc->notify_ios, match_client_io, io);
+ if (!client)
+ return false;
+ }
- io_destroy(io);
+ client_io_free(client);
return false;
}
@@ -3041,9 +3068,67 @@ static int sock_io_send(struct io *io, const void *data, size_t len)
#endif
}
+static void att_disconnect_cb(int err, void *user_data)
+{
+ struct client_io *client = user_data;
+
+ /* If ATT is disconnected shutdown correspondent client IO so sock_hup
+ * is triggered and the server socket is closed.
+ */
+ io_shutdown(client->io);
+}
+
+static struct client_io *
+client_io_new(struct external_chrc *chrc, int fd, struct bt_att *att)
+{
+ struct client_io *client;
+
+ client = new0(struct client_io, 1);
+ client->att = bt_att_ref(att);
+ client->disconn_id = bt_att_register_disconnect(att, att_disconnect_cb,
+ client, NULL);
+ client->io = sock_io_new(fd, chrc);
+
+ return client;
+}
+
+static bool match_client_att(const void *data, const void *user_data)
+{
+ const struct client_io *client = data;
+ const struct bt_att *att = user_data;
+
+ /* Always match if ATT instance is not set since that is used by
+ * clear_cc_state to clear all instances.
+ */
+ if (!att)
+ return true;
+
+ return client->att == att;
+}
+
+static struct client_io *
+client_write_io_get(struct external_chrc *chrc, int fd, struct bt_att *att)
+{
+ struct client_io *client;
+
+ client = queue_find(chrc->write_ios, match_client_att, att);
+ if (client)
+ return client;
+
+ client = client_io_new(chrc, fd, att);
+
+ if (!chrc->write_ios)
+ chrc->write_ios = queue_new();
+
+ queue_push_tail(chrc->write_ios, client);
+
+ return client;
+}
+
static void acquire_write_reply(DBusMessage *message, void *user_data)
{
struct pending_op *op = user_data;
+ struct client_io *client;
struct external_chrc *chrc;
DBusError err;
int fd;
@@ -3084,10 +3169,12 @@ static void acquire_write_reply(DBusMessage *message, void *user_data)
DBG("AcquireWrite success: fd %d MTU %u\n", fd, mtu);
- chrc->write_io = sock_io_new(fd, chrc);
+ client = client_write_io_get(chrc, fd, op->att);
+ if (!client)
+ goto retry;
while ((op = queue_peek_head(chrc->pending_writes)) != NULL) {
- if (sock_io_send(chrc->write_io, op->data.iov_base,
+ if (sock_io_send(client->io, op->data.iov_base,
op->data.iov_len) < 0)
goto retry;
@@ -3148,6 +3235,27 @@ static struct pending_op *acquire_write(struct external_chrc *chrc,
return NULL;
}
+static struct client_io *
+client_notify_io_get(struct external_chrc *chrc, int fd, struct bt_att *att)
+{
+ struct client_io *client;
+
+ client = queue_find(chrc->notify_ios, match_client_att, att);
+ if (client)
+ return client;
+
+ client = client_io_new(chrc, fd, att);
+
+ io_set_read_handler(client->io, sock_io_read, chrc, NULL);
+
+ if (!chrc->notify_ios)
+ chrc->notify_ios = queue_new();
+
+ queue_push_tail(chrc->notify_ios, client);
+
+ return client;
+}
+
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
static void start_notify_setup(DBusMessageIter *iter, void *user_data)
{
@@ -3169,6 +3277,7 @@ static void acquire_notify_reply(DBusMessage *message, void *user_data)
{
struct pending_op *op = user_data;
struct external_chrc *chrc = (void *) op->data.iov_base;
+ struct client_io *client;
DBusError err;
int fd;
uint16_t mtu;
@@ -3202,8 +3311,9 @@ static void acquire_notify_reply(DBusMessage *message, void *user_data)
DBG("AcquireNotify success: fd %d MTU %u\n", fd, mtu);
- chrc->notify_io = sock_io_new(fd, chrc);
- io_set_read_handler(chrc->notify_io, sock_io_read, chrc, NULL);
+ client = client_notify_io_get(chrc, fd, op->att);
+ if (!client)
+ goto retry;
__sync_fetch_and_add(&chrc->ntfy_cnt, 1);
@@ -3257,6 +3367,7 @@ static void stop_notify_setup(DBusMessageIter *iter, void *user_data)
static uint8_t ccc_write_cb(struct pending_op *op, void *user_data)
{
struct external_chrc *chrc = user_data;
+ struct client_io *client;
DBusMessageIter iter;
uint16_t value;
@@ -3269,18 +3380,19 @@ static uint8_t ccc_write_cb(struct pending_op *op, void *user_data)
if (!chrc->ntfy_cnt)
goto done;
- if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1))
+ client = queue_remove_if(chrc->notify_ios, match_client_att,
+ op ? op->att : NULL);
+ if (client) {
+ client_io_free(client);
+ __sync_sub_and_fetch(&chrc->ntfy_cnt, 1);
goto done;
-
- if (chrc->notify_io) {
- io_destroy(chrc->notify_io);
- chrc->notify_io = NULL;
+ }
+ if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1))
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
DBG("HUP is not getting generated so calling StopNotify");
#else
goto done;
#endif
- }
/*
* Send request to stop notifying. This is best-effort
@@ -3310,7 +3422,8 @@ static uint8_t ccc_write_cb(struct pending_op *op, void *user_data)
(value == 2 && !(chrc->props & BT_GATT_CHRC_PROP_INDICATE)))
return BT_ERROR_CCC_IMPROPERLY_CONFIGURED;
- if (chrc->notify_io) {
+ client = queue_find(chrc->notify_ios, match_client_att, op->att);
+ if (client) {
__sync_fetch_and_add(&chrc->ntfy_cnt, 1);
goto done;
}
@@ -3726,6 +3839,7 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
struct external_chrc *chrc = user_data;
+ struct client_io *client;
struct btd_device *device;
struct queue *queue;
DBusMessageIter iter;
@@ -3765,8 +3879,9 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib,
if (opcode == BT_ATT_OP_EXEC_WRITE_REQ)
chrc->prep_authorized = false;
- if (chrc->write_io) {
- if (sock_io_send(chrc->write_io, value, len) < 0) {
+ client = queue_find(chrc->write_ios, match_client_att, att);
+ if (client) {
+ if (sock_io_send(client->io, value, len) < 0) {
error("Unable to write: %s", strerror(errno));
goto fail;
}