2017-05-02 08:28:29

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH BlueZ 0/2] Service caching improvements

Service discovery is performed after reconnect and after
receiving service changed indication. In current implementation
Bluez does not remove cached services if they were not found in
next discovery and no new services were put in their range.
This patch set removes services which were previously found in
range but were not found in current service discovery.

Marcin Kraglak (2):
shared/gatt-db: Remove services with match function
shared/gatt-client: Validate services

src/shared/gatt-client.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.c | 41 ++++++++++++++++++++++++++
src/shared/gatt-db.h | 7 +++++
3 files changed, 124 insertions(+)

--
2.4.3



2017-05-02 08:28:31

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH BlueZ 2/2] shared/gatt-client: Validate cached services

Remove services that were not found in current discovery.
---
src/shared/gatt-client.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 0134721..ce19e38 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -920,6 +920,72 @@ done:
discovery_op_complete(op, success, att_ecode);
}

+struct validate_svc_data {
+ struct bt_gatt_result *result;
+ uint16_t start, end;
+ bool primary;
+};
+
+static bool validate_svc_cb(struct gatt_db_attribute *attrib,
+ void *user_data)
+{
+ struct validate_svc_data *data = user_data;
+ uint16_t service_start_h, service_end_h;
+ struct bt_gatt_iter iter;
+ bt_uuid_t service_uuid;
+ uint128_t u128;
+ bool primary;
+
+ gatt_db_attribute_get_service_data(attrib, &service_start_h,
+ &service_end_h, &primary,
+ &service_uuid);
+
+ if (primary != data->primary)
+ return false;
+
+ if (data->start > service_start_h || data->end < service_start_h)
+ return false;
+
+ if (data->result) {
+ uint16_t start_h, end_h;
+
+ bt_gatt_iter_init(&iter, data->result);
+
+ while (bt_gatt_iter_next_service(&iter, &start_h, &end_h,
+ u128.data)) {
+ bt_uuid_t uuid;
+
+ if (start_h != service_start_h)
+ continue;
+
+ if (end_h != service_end_h)
+ continue;
+
+ bt_uuid128_create(&uuid, u128);
+ if (bt_uuid_cmp(&uuid, &service_uuid))
+ continue;
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void validate_services(struct gatt_db *db, uint16_t start,
+ uint16_t end, bool primary,
+ struct bt_gatt_result *result)
+{
+ struct validate_svc_data data = {
+ .start = start,
+ .end = end,
+ .primary = primary,
+ .result = result,
+ };
+
+ gatt_db_remove_services(db, validate_svc_cb, &data);
+}
+
static void discover_secondary_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -939,6 +1005,9 @@ static void discover_secondary_cb(bool success, uint8_t att_ecode,
util_debug(client->debug_callback, client->debug_data,
"Secondary service discovery failed."
" ATT ECODE: 0x%02x", att_ecode);
+
+ validate_services(client->db, op->start, op->end, false, NULL);
+
switch (att_ecode) {
case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND:
case BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE:
@@ -957,6 +1026,8 @@ static void discover_secondary_cb(bool success, uint8_t att_ecode,
"Secondary services found: %u",
bt_gatt_result_service_count(result));

+ validate_services(client->db, op->start, op->end, false, result);
+
while (bt_gatt_iter_next_service(&iter, &start, &end, u128.data)) {
bt_uuid128_create(&uuid, u128);

@@ -1051,6 +1122,9 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
util_debug(client->debug_callback, client->debug_data,
"Primary service discovery failed."
" ATT ECODE: 0x%02x", att_ecode);
+
+ validate_services(client->db, op->start, op->end, true, NULL);
+
/* Reset error in case of not found */
switch (att_ecode) {
case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND:
@@ -1071,6 +1145,8 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
"Primary services found: %u",
bt_gatt_result_service_count(result));

+ validate_services(client->db, op->start, op->end, true, result);
+
while (bt_gatt_iter_next_service(&iter, &start, &end, u128.data)) {
bt_uuid128_create(&uuid, u128);

--
2.4.3


2017-05-02 08:28:30

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH BlueZ 1/2] shared/gatt-db: Remove services with match function

Allow remove services using match callback.
---
src/shared/gatt-db.c | 41 +++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 7 +++++++
2 files changed, 48 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 8ef6f3b..ded7561 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -408,6 +408,47 @@ bool gatt_db_remove_service(struct gatt_db *db,
return true;
}

+struct remove_services_data {
+ gatt_db_attribute_match_cb_t func;
+ void *user_data;
+};
+
+static bool remove_services_match(const void *data, const void *match_data)
+{
+ const struct remove_services_data *remove_svc_data = match_data;
+ const struct gatt_db_service *service = data;
+ struct gatt_db_attribute *attrib = service->attributes[0];
+
+ return remove_svc_data->func(attrib, remove_svc_data->user_data);
+}
+
+bool gatt_db_remove_services(struct gatt_db *db,
+ gatt_db_attribute_match_cb_t func,
+ void *user_data)
+{
+ if (!db)
+ return false;
+
+ if (func) {
+ struct remove_services_data remove_services_data = {
+ .func = func,
+ .user_data = user_data,
+ };
+
+ queue_remove_all(db->services, remove_services_match,
+ &remove_services_data,
+ gatt_db_service_destroy);
+ } else {
+ queue_remove_all(db->services, NULL, NULL,
+ gatt_db_service_destroy);
+ }
+
+ if (gatt_db_isempty(db))
+ db->next_handle = 0;
+
+ return true;
+}
+
bool gatt_db_clear(struct gatt_db *db)
{
return gatt_db_clear_range(db, 1, UINT16_MAX);
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 134ec63..4e049cd 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -38,6 +38,13 @@ struct gatt_db_attribute *gatt_db_add_service(struct gatt_db *db,

bool gatt_db_remove_service(struct gatt_db *db,
struct gatt_db_attribute *attrib);
+
+typedef bool (*gatt_db_attribute_match_cb_t)(struct gatt_db_attribute *attrib,
+ void *user_data);
+
+bool gatt_db_remove_services(struct gatt_db *db,
+ gatt_db_attribute_match_cb_t func,
+ void *user_data);
bool gatt_db_clear(struct gatt_db *db);
bool gatt_db_clear_range(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle);
--
2.4.3