linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v0 0/7] Add removing GATT services
@ 2014-04-02 18:30 Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 1/7] gatt: Add helper for " Claudio Takahasi
                   ` (7 more replies)
  0 siblings, 8 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi

This patchset implements GattManager1.UnregisterService(), and low-level
functions to remove service declarations (and its attributes) from the
attribute database.

Andre Guedes (1):
  gatt: Add helper for removing GATT services

Claudio Takahasi (6):
  gdbus: Avoid reporting GDBusClient disconnect twice
  gatt: Rename external_app to external_service
  gatt: Add GattManager1.UnregisterService()
  gatt: Add removing service from the database
  gatt: Fix possibly lost block when bluetoothd exits
  doc: Add InvalidArguments to UnregisterService() errors

 doc/gatt-api.txt |   3 +-
 gdbus/client.c   |  14 ++++-
 src/gatt-dbus.c  | 162 ++++++++++++++++++++++++++++++++++---------------------
 src/gatt.c       |  42 +++++++++++++++
 src/gatt.h       |   7 +++
 5 files changed, 165 insertions(+), 63 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v0 1/7] gatt: Add helper for removing GATT services
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
@ 2014-04-02 18:30 ` Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 2/7] gdbus: Avoid reporting GDBusClient disconnect twice Claudio Takahasi
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi; +Cc: Andre Guedes

From: Andre Guedes <andre.guedes@openbossa.org>

This patch adds the btd_gatt_remove_service() helper which removes a GATT
primary (or secondary) Service declaration (including its characteristics)
from the local attribute database.
---
 src/gatt.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 src/gatt.h |  7 +++++++
 2 files changed, 49 insertions(+)

diff --git a/src/gatt.c b/src/gatt.c
index f07effa..3060462 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -26,6 +26,7 @@
 #endif
 
 #include <glib.h>
+#include <stdbool.h>
 
 #include "log.h"
 #include "lib/uuid.h"
@@ -104,6 +105,18 @@ static struct btd_attribute *new_attribute(const bt_uuid_t *type,
 	return attr;
 }
 
+static bool is_service(const struct btd_attribute *attr)
+{
+	if (attr->type.type != BT_UUID16)
+		return false;
+
+	if (attr->type.value.u16 == GATT_PRIM_SVC_UUID ||
+			attr->type.value.u16 == GATT_SND_SVC_UUID)
+		return true;
+
+	return false;
+}
+
 static int local_database_add(uint16_t handle, struct btd_attribute *attr)
 {
 	attr->handle = handle;
@@ -149,6 +162,35 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	return attr;
 }
 
+void btd_gatt_remove_service(struct btd_attribute *service)
+{
+	GList *list = g_list_find(local_attribute_db, service);
+	bool first_node;
+
+	if (!list)
+		return;
+
+	first_node = local_attribute_db == list;
+
+	/* Remove service declaration attribute */
+	free(list->data);
+	list = g_list_delete_link(list, list);
+
+	/* Remove all characteristics until next service declaration */
+	while (list && !is_service(list->data)) {
+		free(list->data);
+		list = g_list_delete_link(list, list);
+	}
+
+	/*
+	 * When removing the first node, local attribute database head
+	 * needs to be updated. Node removed from middle doesn't change
+	 * the list head address.
+	 */
+	if (first_node)
+		local_attribute_db = list;
+}
+
 struct btd_attribute *btd_gatt_add_char(const bt_uuid_t *uuid,
 						uint8_t properties,
 						btd_attr_read_t read_cb,
diff --git a/src/gatt.h b/src/gatt.h
index da7af92..f16541e 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -81,6 +81,13 @@ typedef void (*btd_attr_write_t) (struct btd_attribute *attr,
 struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
 
 /*
+ * btd_gatt_remove_service - Remove a service (along with all its
+ * characteristics) from the local attribute database.
+ * @service:	Service declaration attribute.
+ */
+void btd_gatt_remove_service(struct btd_attribute *service);
+
+/*
  * btd_gatt_add_char - Add a characteristic (declaration and value attributes)
  * to local attribute database.
  * @uuid:	Characteristic UUID (16-bits or 128-bits).
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v0 2/7] gdbus: Avoid reporting GDBusClient disconnect twice
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 1/7] gatt: Add helper for " Claudio Takahasi
@ 2014-04-02 18:30 ` Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 3/7] gatt: Rename external_app to external_service Claudio Takahasi
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi

No matter if disconnection was reported previously, g_dbus_client_unref()
was always calling service disconnect callback. This patch fix the
following scenario:
1) service disconnects from the bus
2) disconnect callback gets called
3) client calls g_dbus_client_unref(), disconnect callback is called
   again.
---
 gdbus/client.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/gdbus/client.c b/gdbus/client.c
index 3bf883a..eb68a0f 100644
--- a/gdbus/client.c
+++ b/gdbus/client.c
@@ -51,6 +51,7 @@ struct GDBusClient {
 	GDBusWatchFunction connect_func;
 	void *connect_data;
 	GDBusWatchFunction disconn_func;
+	gboolean connected;
 	void *disconn_data;
 	GDBusMessageFunction signal_func;
 	void *signal_data;
@@ -1146,6 +1147,8 @@ static void service_connect(DBusConnection *conn, void *user_data)
 
 	get_managed_objects(client);
 
+	client->connected = TRUE;
+
 	g_dbus_client_unref(client);
 }
 
@@ -1156,8 +1159,10 @@ static void service_disconnect(DBusConnection *conn, void *user_data)
 	g_list_free_full(client->proxy_list, proxy_free);
 	client->proxy_list = NULL;
 
-	if (client->disconn_func)
+	if (client->disconn_func) {
 		client->disconn_func(conn, client->disconn_data);
+		client->connected = FALSE;
+	}
 }
 
 static DBusHandlerResult message_filter(DBusConnection *connection,
@@ -1210,6 +1215,7 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
 	client->dbus_conn = dbus_connection_ref(connection);
 	client->service_name = g_strdup(service);
 	client->base_path = g_strdup(path);
+	client->connected = FALSE;
 
 	client->match_rules = g_ptr_array_sized_new(1);
 	g_ptr_array_set_free_func(client->match_rules, g_free);
@@ -1284,7 +1290,11 @@ void g_dbus_client_unref(GDBusClient *client)
 
 	g_list_free_full(client->proxy_list, proxy_free);
 
-	if (client->disconn_func)
+	/*
+	 * Don't call disconn_func twice if disconnection
+	 * was previously reported.
+	 */
+	if (client->disconn_func && client->connected)
 		client->disconn_func(client->dbus_conn, client->disconn_data);
 
 	g_dbus_remove_watch(client->dbus_conn, client->watch);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v0 3/7] gatt: Rename external_app to external_service
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 1/7] gatt: Add helper for " Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 2/7] gdbus: Avoid reporting GDBusClient disconnect twice Claudio Takahasi
@ 2014-04-02 18:30 ` Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 4/7] gatt: Add GattManager1.UnregisterService() Claudio Takahasi
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi

Even for external applications providing multiple services, each
external service should have its own instance of GDBusClient. This
approach allows a more dynamic management of the registered services.
Based on this assumption, rename the external_app to external_service
is more logical.
---
 src/gatt-dbus.c | 107 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 54 insertions(+), 53 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 1bfa21f..b29371d 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -50,7 +50,7 @@
 #define GATT_CHR_IFACE			"org.bluez.GattCharacteristic1"
 #define GATT_DESCRIPTOR_IFACE		"org.bluez.GattDescriptor1"
 
-struct external_app {
+struct external_service {
 	char *owner;
 	char *path;
 	DBusMessage *reg;
@@ -70,31 +70,31 @@ struct proxy_write_data {
  */
 static GHashTable *proxy_hash;
 
-static GSList *external_apps;
+static GSList *external_services;
 
-static int external_app_path_cmp(gconstpointer a, gconstpointer b)
+static int external_service_path_cmp(gconstpointer a, gconstpointer b)
 {
-	const struct external_app *eapp = a;
+	const struct external_service *esvc = a;
 	const char *path = b;
 
-	return g_strcmp0(eapp->path, path);
+	return g_strcmp0(esvc->path, path);
 }
 
-static void external_app_watch_destroy(gpointer user_data)
+static void external_service_watch_destroy(gpointer user_data)
 {
-	struct external_app *eapp = user_data;
+	struct external_service *esvc = user_data;
 
 	/* TODO: Remove from the database */
 
-	external_apps = g_slist_remove(external_apps, eapp);
+	external_services = g_slist_remove(external_services, esvc);
 
-	g_dbus_client_unref(eapp->client);
-	if (eapp->reg)
-		dbus_message_unref(eapp->reg);
+	g_dbus_client_unref(esvc->client);
+	if (esvc->reg)
+		dbus_message_unref(esvc->reg);
 
-	g_free(eapp->owner);
-	g_free(eapp->path);
-	g_free(eapp);
+	g_free(esvc->owner);
+	g_free(esvc->path);
+	g_free(esvc);
 }
 
 static int proxy_path_cmp(gconstpointer a, gconstpointer b)
@@ -167,13 +167,13 @@ fail:
 
 static void proxy_added(GDBusProxy *proxy, void *user_data)
 {
-	struct external_app *eapp = user_data;
+	struct external_service *esvc = user_data;
 	const char *interface, *path;
 
 	interface = g_dbus_proxy_get_interface(proxy);
 	path = g_dbus_proxy_get_path(proxy);
 
-	if (!g_str_has_prefix(path, eapp->path))
+	if (!g_str_has_prefix(path, esvc->path))
 		return;
 
 	if (g_strcmp0(interface, GATT_CHR_IFACE) != 0 &&
@@ -188,13 +188,13 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
 	 * proxies sorted by path helps the logic to register the
 	 * object path later.
 	 */
-	eapp->proxies = g_slist_insert_sorted(eapp->proxies, proxy,
+	esvc->proxies = g_slist_insert_sorted(esvc->proxies, proxy,
 							proxy_path_cmp);
 }
 
 static void proxy_removed(GDBusProxy *proxy, void *user_data)
 {
-	struct external_app *eapp = user_data;
+	struct external_service *esvc = user_data;
 	const char *interface, *path;
 
 	interface = g_dbus_proxy_get_interface(proxy);
@@ -202,7 +202,7 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 
 	DBG("path %s iface %s", path, interface);
 
-	eapp->proxies = g_slist_remove(eapp->proxies, proxy);
+	esvc->proxies = g_slist_remove(esvc->proxies, proxy);
 }
 
 static void proxy_read_cb(struct btd_attribute *attr,
@@ -323,7 +323,7 @@ static void proxy_write_cb(struct btd_attribute *attr,
 
 }
 
-static int register_external_service(const struct external_app *eapp,
+static int register_external_service(const struct external_service *esvc,
 							GDBusProxy *proxy)
 {
 	DBusMessageIter iter;
@@ -332,7 +332,7 @@ static int register_external_service(const struct external_app *eapp,
 
 	path = g_dbus_proxy_get_path(proxy);
 	iface = g_dbus_proxy_get_interface(proxy);
-	if (g_strcmp0(eapp->path, path) != 0 ||
+	if (g_strcmp0(esvc->path, path) != 0 ||
 			g_strcmp0(iface, GATT_SERVICE_IFACE) != 0)
 		return -EINVAL;
 
@@ -450,43 +450,43 @@ static int register_external_characteristics(GSList *proxies)
 
 static void client_ready(GDBusClient *client, void *user_data)
 {
-	struct external_app *eapp = user_data;
+	struct external_service *esvc = user_data;
 	GDBusProxy *proxy;
 	DBusConnection *conn = btd_get_dbus_connection();
 	DBusMessage *reply;
 
-	if (!eapp->proxies)
+	if (!esvc->proxies)
 		goto fail;
 
-	proxy = eapp->proxies->data;
-	if (register_external_service(eapp, proxy) < 0)
+	proxy = esvc->proxies->data;
+	if (register_external_service(esvc, proxy) < 0)
 		goto fail;
 
-	if (register_external_characteristics(g_slist_next(eapp->proxies)) < 0)
+	if (register_external_characteristics(g_slist_next(esvc->proxies)) < 0)
 		goto fail;
 
-	DBG("Added GATT service %s", eapp->path);
+	DBG("Added GATT service %s", esvc->path);
 
-	reply = dbus_message_new_method_return(eapp->reg);
+	reply = dbus_message_new_method_return(esvc->reg);
 	goto reply;
 
 fail:
-	error("Could not register external service: %s", eapp->path);
+	error("Could not register external service: %s", esvc->path);
 
-	reply = btd_error_invalid_args(eapp->reg);
-	/* TODO: missing eapp/database cleanup */
+	reply = btd_error_invalid_args(esvc->reg);
+	/* TODO: missing esvc/database cleanup */
 
 reply:
-	dbus_message_unref(eapp->reg);
-	eapp->reg = NULL;
+	dbus_message_unref(esvc->reg);
+	esvc->reg = NULL;
 
 	g_dbus_send_message(conn, reply);
 }
 
-static struct external_app *new_external_app(DBusConnection *conn,
+static struct external_service *new_external_service(DBusConnection *conn,
 					DBusMessage *msg, const char *path)
 {
-	struct external_app *eapp;
+	struct external_service *esvc;
 	GDBusClient *client;
 	const char *sender = dbus_message_get_sender(msg);
 
@@ -494,33 +494,33 @@ static struct external_app *new_external_app(DBusConnection *conn,
 	if (!client)
 		return NULL;
 
-	eapp = g_new0(struct external_app, 1);
+	esvc = g_new0(struct external_service, 1);
 
-	eapp->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
-			sender, NULL, eapp, external_app_watch_destroy);
-	if (eapp->watch == 0) {
+	esvc->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+			sender, NULL, esvc, external_service_watch_destroy);
+	if (esvc->watch == 0) {
 		g_dbus_client_unref(client);
-		g_free(eapp);
+		g_free(esvc);
 		return NULL;
 	}
 
-	eapp->owner = g_strdup(sender);
-	eapp->reg = dbus_message_ref(msg);
-	eapp->client = client;
-	eapp->path = g_strdup(path);
+	esvc->owner = g_strdup(sender);
+	esvc->reg = dbus_message_ref(msg);
+	esvc->client = client;
+	esvc->path = g_strdup(path);
 
 	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
-								NULL, eapp);
+								NULL, esvc);
 
-	g_dbus_client_set_ready_watch(client, client_ready, eapp);
+	g_dbus_client_set_ready_watch(client, client_ready, esvc);
 
-	return eapp;
+	return esvc;
 }
 
 static DBusMessage *register_service(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
-	struct external_app *eapp;
+	struct external_service *esvc;
 	DBusMessageIter iter;
 	const char *path;
 
@@ -532,16 +532,17 @@ static DBusMessage *register_service(DBusConnection *conn,
 
 	dbus_message_iter_get_basic(&iter, &path);
 
-	if (g_slist_find_custom(external_apps, path, external_app_path_cmp))
+	if (g_slist_find_custom(external_services, path,
+						external_service_path_cmp))
 		return btd_error_already_exists(msg);
 
-	eapp = new_external_app(conn, msg, path);
-	if (!eapp)
+	esvc = new_external_service(conn, msg, path);
+	if (!esvc)
 		return btd_error_failed(msg, "Not enough resources");
 
-	external_apps = g_slist_prepend(external_apps, eapp);
+	external_services = g_slist_prepend(external_services, esvc);
 
-	DBG("New app %p: %s", eapp, path);
+	DBG("New service %p: %s", esvc, path);
 
 	return NULL;
 }
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v0 4/7] gatt: Add GattManager1.UnregisterService()
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
                   ` (2 preceding siblings ...)
  2014-04-02 18:30 ` [PATCH BlueZ v0 3/7] gatt: Rename external_app to external_service Claudio Takahasi
@ 2014-04-02 18:30 ` Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 5/7] gatt: Add removing service from the database Claudio Takahasi
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi

This patch adds GattManager1.UnregisterService() method implementation
according to doc/gatt-api.txt.
---
 src/gatt-dbus.c | 64 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 47 insertions(+), 17 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index b29371d..3ded9cd 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -56,7 +56,6 @@ struct external_service {
 	DBusMessage *reg;
 	GDBusClient *client;
 	GSList *proxies;
-	unsigned int watch;
 };
 
 struct proxy_write_data {
@@ -80,21 +79,35 @@ static int external_service_path_cmp(gconstpointer a, gconstpointer b)
 	return g_strcmp0(esvc->path, path);
 }
 
-static void external_service_watch_destroy(gpointer user_data)
+static gboolean external_service_destroy(void *user_data)
 {
 	struct external_service *esvc = user_data;
 
-	/* TODO: Remove from the database */
-
-	external_services = g_slist_remove(external_services, esvc);
-
 	g_dbus_client_unref(esvc->client);
+
 	if (esvc->reg)
 		dbus_message_unref(esvc->reg);
 
 	g_free(esvc->owner);
 	g_free(esvc->path);
 	g_free(esvc);
+
+	return FALSE;
+}
+
+static void remove_service(DBusConnection *conn, void *user_data)
+{
+	struct external_service *esvc = user_data;
+
+	/* TODO: Remove from the database */
+
+	external_services = g_slist_remove(external_services, esvc);
+
+	/*
+	 * Do not run in the same loop, this may be a disconnect
+	 * watch call and GDBusClient should not be destroyed.
+	 */
+	g_idle_add(external_service_destroy, esvc);
 }
 
 static int proxy_path_cmp(gconstpointer a, gconstpointer b)
@@ -483,7 +496,7 @@ reply:
 	g_dbus_send_message(conn, reply);
 }
 
-static struct external_service *new_external_service(DBusConnection *conn,
+static struct external_service *external_service_new(DBusConnection *conn,
 					DBusMessage *msg, const char *path)
 {
 	struct external_service *esvc;
@@ -495,20 +508,13 @@ static struct external_service *new_external_service(DBusConnection *conn,
 		return NULL;
 
 	esvc = g_new0(struct external_service, 1);
-
-	esvc->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
-			sender, NULL, esvc, external_service_watch_destroy);
-	if (esvc->watch == 0) {
-		g_dbus_client_unref(client);
-		g_free(esvc);
-		return NULL;
-	}
-
 	esvc->owner = g_strdup(sender);
 	esvc->reg = dbus_message_ref(msg);
 	esvc->client = client;
 	esvc->path = g_strdup(path);
 
+	g_dbus_client_set_disconnect_watch(client, remove_service, esvc);
+
 	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
 								NULL, esvc);
 
@@ -536,7 +542,7 @@ static DBusMessage *register_service(DBusConnection *conn,
 						external_service_path_cmp))
 		return btd_error_already_exists(msg);
 
-	esvc = new_external_service(conn, msg, path);
+	esvc = external_service_new(conn, msg, path);
 	if (!esvc)
 		return btd_error_failed(msg, "Not enough resources");
 
@@ -550,6 +556,30 @@ static DBusMessage *register_service(DBusConnection *conn,
 static DBusMessage *unregister_service(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
+	struct external_service *esvc;
+	DBusMessageIter iter;
+	const char *path;
+	GSList *list;
+
+	if (!dbus_message_iter_init(msg, &iter))
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&iter, &path);
+
+	list = g_slist_find_custom(external_services, path,
+						external_service_path_cmp);
+	if (!list)
+		return btd_error_does_not_exist(msg);
+
+	esvc = list->data;
+	if (!strcmp(dbus_message_get_sender(msg), esvc->owner))
+		return btd_error_does_not_exist(msg);
+
+	remove_service(conn, esvc);
+
 	return dbus_message_new_method_return(msg);
 }
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v0 5/7] gatt: Add removing service from the database
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
                   ` (3 preceding siblings ...)
  2014-04-02 18:30 ` [PATCH BlueZ v0 4/7] gatt: Add GattManager1.UnregisterService() Claudio Takahasi
@ 2014-04-02 18:30 ` Claudio Takahasi
  2014-04-03  7:49   ` Johan Hedberg
  2014-04-02 18:30 ` [PATCH BlueZ v0 6/7] gatt: Fix possibly lost block when bluetoothd exits Claudio Takahasi
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi

This patch removes the service declaration and its attributes when
the external service implementation leaves the system bus, calls
UnregisterService(), or RegisterService() fails.
---
 src/gatt-dbus.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 3ded9cd..17c3359 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -56,6 +56,7 @@ struct external_service {
 	DBusMessage *reg;
 	GDBusClient *client;
 	GSList *proxies;
+	struct btd_attribute *service;
 };
 
 struct proxy_write_data {
@@ -99,7 +100,8 @@ static void remove_service(DBusConnection *conn, void *user_data)
 {
 	struct external_service *esvc = user_data;
 
-	/* TODO: Remove from the database */
+	if (esvc->service)
+		btd_gatt_remove_service(esvc->service);
 
 	external_services = g_slist_remove(external_services, esvc);
 
@@ -336,7 +338,7 @@ static void proxy_write_cb(struct btd_attribute *attr,
 
 }
 
-static int register_external_service(const struct external_service *esvc,
+static int register_external_service(struct external_service *esvc,
 							GDBusProxy *proxy)
 {
 	DBusMessageIter iter;
@@ -360,7 +362,8 @@ static int register_external_service(const struct external_service *esvc,
 	if (bt_string_to_uuid(&uuid, str) < 0)
 		return -EINVAL;
 
-	if (!btd_gatt_add_service(&uuid))
+	esvc->service = btd_gatt_add_service(&uuid);
+	if (!esvc->service)
 		return -EINVAL;
 
 	return 0;
@@ -487,7 +490,8 @@ fail:
 	error("Could not register external service: %s", esvc->path);
 
 	reply = btd_error_invalid_args(esvc->reg);
-	/* TODO: missing esvc/database cleanup */
+	if (esvc->service)
+		btd_gatt_remove_service(esvc->service);
 
 reply:
 	dbus_message_unref(esvc->reg);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v0 6/7] gatt: Fix possibly lost block when bluetoothd exits
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
                   ` (4 preceding siblings ...)
  2014-04-02 18:30 ` [PATCH BlueZ v0 5/7] gatt: Add removing service from the database Claudio Takahasi
@ 2014-04-02 18:30 ` Claudio Takahasi
  2014-04-02 18:30 ` [PATCH BlueZ v0 7/7] doc: Add InvalidArguments to UnregisterService() errors Claudio Takahasi
  2014-04-03 19:46 ` [PATCH BlueZ v1 0/3] Add removing GATT services Claudio Takahasi
  7 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi

This patch fixes a possibly lost memory related to GDBusClient
and GDBusProxy objects when bluetoothd daemon exits and there
is registered external service.
==1503==    by 0x47ECFB: g_dbus_client_new (client.c:1232)
==1503==    by 0x461EC7: register_service (gatt-dbus.c:510)
---
 src/gatt-dbus.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 17c3359..1a0e55e 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -96,6 +96,11 @@ static gboolean external_service_destroy(void *user_data)
 	return FALSE;
 }
 
+static void external_service_free(void *user_data)
+{
+	external_service_destroy(user_data);
+}
+
 static void remove_service(DBusConnection *conn, void *user_data)
 {
 	struct external_service *esvc = user_data;
@@ -622,6 +627,8 @@ void gatt_dbus_manager_unregister(void)
 	g_hash_table_destroy(proxy_hash);
 	proxy_hash = NULL;
 
+	g_slist_free_full(external_services, external_service_free);
+
 	g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
 							GATT_MGR_IFACE);
 }
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v0 7/7] doc: Add InvalidArguments to UnregisterService() errors
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
                   ` (5 preceding siblings ...)
  2014-04-02 18:30 ` [PATCH BlueZ v0 6/7] gatt: Fix possibly lost block when bluetoothd exits Claudio Takahasi
@ 2014-04-02 18:30 ` Claudio Takahasi
  2014-04-03 19:46 ` [PATCH BlueZ v1 0/3] Add removing GATT services Claudio Takahasi
  7 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-02 18:30 UTC (permalink / raw)
  To: linux-bluetooth, claudio.takahasi

This patch adds "org.bluez.Error.InvalidArguments" as possible error
returned by GattManager1.UnregisterService().
---
 doc/gatt-api.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index deb519b..8c7975c 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -145,4 +145,5 @@ Methods		RegisterService(object service, dict options)
 			must match the same value that has been used
 			on registration.
 
-			Possible errors: org.bluez.Error.DoesNotExist
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.DoesNotExist
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH BlueZ v0 5/7] gatt: Add removing service from the database
  2014-04-02 18:30 ` [PATCH BlueZ v0 5/7] gatt: Add removing service from the database Claudio Takahasi
@ 2014-04-03  7:49   ` Johan Hedberg
  2014-04-03 19:12     ` Claudio Takahasi
  0 siblings, 1 reply; 15+ messages in thread
From: Johan Hedberg @ 2014-04-03  7:49 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth

Hi Claudio,

On Wed, Apr 02, 2014, Claudio Takahasi wrote:
> This patch removes the service declaration and its attributes when
> the external service implementation leaves the system bus, calls
> UnregisterService(), or RegisterService() fails.
> ---
>  src/gatt-dbus.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)

I've applied patches 1-4.

> @@ -99,7 +100,8 @@ static void remove_service(DBusConnection *conn, void *user_data)
>  {
>  	struct external_service *esvc = user_data;
>  
> -	/* TODO: Remove from the database */
> +	if (esvc->service)
> +		btd_gatt_remove_service(esvc->service);

Would it not be safer to set esvc->service to NULL after this?

> @@ -360,7 +362,8 @@ static int register_external_service(const struct external_service *esvc,
>  	if (bt_string_to_uuid(&uuid, str) < 0)
>  		return -EINVAL;
>  
> -	if (!btd_gatt_add_service(&uuid))
> +	esvc->service = btd_gatt_add_service(&uuid);
> +	if (!esvc->service)
>  		return -EINVAL;
>  
>  	return 0;
> @@ -487,7 +490,8 @@ fail:
>  	error("Could not register external service: %s", esvc->path);
>  
>  	reply = btd_error_invalid_args(esvc->reg);
> -	/* TODO: missing esvc/database cleanup */
> +	if (esvc->service)
> +		btd_gatt_remove_service(esvc->service);

Same here.

Johan

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH BlueZ v0 5/7] gatt: Add removing service from the database
  2014-04-03  7:49   ` Johan Hedberg
@ 2014-04-03 19:12     ` Claudio Takahasi
  0 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-03 19:12 UTC (permalink / raw)
  To: Claudio Takahasi, BlueZ development

Hi Johan:

On Thu, Apr 3, 2014 at 4:49 AM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi Claudio,
>
> On Wed, Apr 02, 2014, Claudio Takahasi wrote:
>> This patch removes the service declaration and its attributes when
>> the external service implementation leaves the system bus, calls
>> UnregisterService(), or RegisterService() fails.
>> ---
>>  src/gatt-dbus.c | 12 ++++++++----
>>  1 file changed, 8 insertions(+), 4 deletions(-)
>
> I've applied patches 1-4.
>
>> @@ -99,7 +100,8 @@ static void remove_service(DBusConnection *conn, void *user_data)
>>  {
>>       struct external_service *esvc = user_data;
>>
>> -     /* TODO: Remove from the database */
>> +     if (esvc->service)
>> +             btd_gatt_remove_service(esvc->service);
>
> Would it not be safer to set esvc->service to NULL after this?
>
>> @@ -360,7 +362,8 @@ static int register_external_service(const struct external_service *esvc,
>>       if (bt_string_to_uuid(&uuid, str) < 0)
>>               return -EINVAL;
>>
>> -     if (!btd_gatt_add_service(&uuid))
>> +     esvc->service = btd_gatt_add_service(&uuid);
>> +     if (!esvc->service)
>>               return -EINVAL;
>>
>>       return 0;
>> @@ -487,7 +490,8 @@ fail:
>>       error("Could not register external service: %s", esvc->path);
>>
>>       reply = btd_error_invalid_args(esvc->reg);
>> -     /* TODO: missing esvc/database cleanup */
>> +     if (esvc->service)
>> +             btd_gatt_remove_service(esvc->service);
>
> Same here.
>
> Johan

Actually, there is a potential invalid memory access related to esvc
(external_service), set esvc->service to NULL is not necessary.

Race condition & invalid memory access can happen when calling
remove_service callback & GDBusClient unref.

I will send another patchset fixing this problem.

Regards,
Claudio

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v1 0/3] Add removing GATT services
  2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
                   ` (6 preceding siblings ...)
  2014-04-02 18:30 ` [PATCH BlueZ v0 7/7] doc: Add InvalidArguments to UnregisterService() errors Claudio Takahasi
@ 2014-04-03 19:46 ` Claudio Takahasi
  2014-04-03 19:46   ` [PATCH BlueZ v1 1/3] gatt: Add removing service from the database Claudio Takahasi
                     ` (3 more replies)
  7 siblings, 4 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-03 19:46 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patchset implements GattManager1.UnregisterService(), and low-level
functions to remove service declarations (and its attributes) from the
attribute database.

Changes v1-v0:
 * Fix potential invalid memory access
 * Cleanup of external service when registration fails

Claudio Takahasi (3):
  gatt: Add removing service from the database
  gatt: Fix possibly lost block when bluetoothd exits
  doc: Add InvalidArguments to UnregisterService() errors

 doc/gatt-api.txt |  3 ++-
 src/gatt-dbus.c  | 51 +++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 43 insertions(+), 11 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v1 1/3] gatt: Add removing service from the database
  2014-04-03 19:46 ` [PATCH BlueZ v1 0/3] Add removing GATT services Claudio Takahasi
@ 2014-04-03 19:46   ` Claudio Takahasi
  2014-04-03 19:46   ` [PATCH BlueZ v1 2/3] gatt: Fix possibly lost block when bluetoothd exits Claudio Takahasi
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-03 19:46 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch removes the service declaration and its attributes when
the external service implementation leaves the system bus, calls
UnregisterService(), or RegisterService() fails.
---
 src/gatt-dbus.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 3ded9cd..d3fd717 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -56,6 +56,7 @@ struct external_service {
 	DBusMessage *reg;
 	GDBusClient *client;
 	GSList *proxies;
+	struct btd_attribute *service;
 };
 
 struct proxy_write_data {
@@ -99,10 +100,11 @@ static void remove_service(DBusConnection *conn, void *user_data)
 {
 	struct external_service *esvc = user_data;
 
-	/* TODO: Remove from the database */
-
 	external_services = g_slist_remove(external_services, esvc);
 
+	if (esvc->service)
+		btd_gatt_remove_service(esvc->service);
+
 	/*
 	 * Do not run in the same loop, this may be a disconnect
 	 * watch call and GDBusClient should not be destroyed.
@@ -336,7 +338,7 @@ static void proxy_write_cb(struct btd_attribute *attr,
 
 }
 
-static int register_external_service(const struct external_service *esvc,
+static int register_external_service(struct external_service *esvc,
 							GDBusProxy *proxy)
 {
 	DBusMessageIter iter;
@@ -360,7 +362,8 @@ static int register_external_service(const struct external_service *esvc,
 	if (bt_string_to_uuid(&uuid, str) < 0)
 		return -EINVAL;
 
-	if (!btd_gatt_add_service(&uuid))
+	esvc->service = btd_gatt_add_service(&uuid);
+	if (!esvc->service)
 		return -EINVAL;
 
 	return 0;
@@ -481,18 +484,25 @@ static void client_ready(GDBusClient *client, void *user_data)
 	DBG("Added GATT service %s", esvc->path);
 
 	reply = dbus_message_new_method_return(esvc->reg);
-	goto reply;
+	g_dbus_send_message(conn, reply);
+
+	dbus_message_unref(esvc->reg);
+	esvc->reg = NULL;
+
+	return;
 
 fail:
 	error("Could not register external service: %s", esvc->path);
 
-	reply = btd_error_invalid_args(esvc->reg);
-	/* TODO: missing esvc/database cleanup */
+	/*
+	 * Set callback to NULL to avoid potential race condition
+	 * when calling remove_service and GDBusClient unref.
+	 */
+	g_dbus_client_set_disconnect_watch(esvc->client, NULL, NULL);
 
-reply:
-	dbus_message_unref(esvc->reg);
-	esvc->reg = NULL;
+	remove_service(conn, esvc);
 
+	reply = btd_error_invalid_args(esvc->reg);
 	g_dbus_send_message(conn, reply);
 }
 
@@ -578,6 +588,12 @@ static DBusMessage *unregister_service(DBusConnection *conn,
 	if (!strcmp(dbus_message_get_sender(msg), esvc->owner))
 		return btd_error_does_not_exist(msg);
 
+	/*
+	 * Set callback to NULL to avoid potential race condition
+	 * when calling remove_service and GDBusClient unref.
+	 */
+	g_dbus_client_set_disconnect_watch(esvc->client, NULL, NULL);
+
 	remove_service(conn, esvc);
 
 	return dbus_message_new_method_return(msg);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v1 2/3] gatt: Fix possibly lost block when bluetoothd exits
  2014-04-03 19:46 ` [PATCH BlueZ v1 0/3] Add removing GATT services Claudio Takahasi
  2014-04-03 19:46   ` [PATCH BlueZ v1 1/3] gatt: Add removing service from the database Claudio Takahasi
@ 2014-04-03 19:46   ` Claudio Takahasi
  2014-04-03 19:46   ` [PATCH BlueZ v1 3/3] doc: Add InvalidArguments to UnregisterService() errors Claudio Takahasi
  2014-04-04  7:30   ` [PATCH BlueZ v1 0/3] Add removing GATT services Johan Hedberg
  3 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-03 19:46 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch fixes a possibly lost memory related to GDBusClient
and GDBusProxy objects when bluetoothd daemon exits and there
is registered external service.
==1503==    by 0x47ECFB: g_dbus_client_new (client.c:1232)
==1503==    by 0x461EC7: register_service (gatt-dbus.c:510)
---
 src/gatt-dbus.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index d3fd717..26437e7 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -96,6 +96,19 @@ static gboolean external_service_destroy(void *user_data)
 	return FALSE;
 }
 
+static void external_service_free(void *user_data)
+{
+	struct external_service *esvc = user_data;
+
+	/*
+	 * Set callback to NULL to avoid potential race condition
+	 * when calling remove_service and GDBusClient unref.
+	 */
+	g_dbus_client_set_disconnect_watch(esvc->client, NULL, NULL);
+
+	external_service_destroy(user_data);
+}
+
 static void remove_service(DBusConnection *conn, void *user_data)
 {
 	struct external_service *esvc = user_data;
@@ -634,6 +647,8 @@ void gatt_dbus_manager_unregister(void)
 	g_hash_table_destroy(proxy_hash);
 	proxy_hash = NULL;
 
+	g_slist_free_full(external_services, external_service_free);
+
 	g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
 							GATT_MGR_IFACE);
 }
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ v1 3/3] doc: Add InvalidArguments to UnregisterService() errors
  2014-04-03 19:46 ` [PATCH BlueZ v1 0/3] Add removing GATT services Claudio Takahasi
  2014-04-03 19:46   ` [PATCH BlueZ v1 1/3] gatt: Add removing service from the database Claudio Takahasi
  2014-04-03 19:46   ` [PATCH BlueZ v1 2/3] gatt: Fix possibly lost block when bluetoothd exits Claudio Takahasi
@ 2014-04-03 19:46   ` Claudio Takahasi
  2014-04-04  7:30   ` [PATCH BlueZ v1 0/3] Add removing GATT services Johan Hedberg
  3 siblings, 0 replies; 15+ messages in thread
From: Claudio Takahasi @ 2014-04-03 19:46 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

This patch adds "org.bluez.Error.InvalidArguments" as possible error
returned by GattManager1.UnregisterService().
---
 doc/gatt-api.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index deb519b..8c7975c 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -145,4 +145,5 @@ Methods		RegisterService(object service, dict options)
 			must match the same value that has been used
 			on registration.
 
-			Possible errors: org.bluez.Error.DoesNotExist
+			Possible errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.DoesNotExist
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH BlueZ v1 0/3] Add removing GATT services
  2014-04-03 19:46 ` [PATCH BlueZ v1 0/3] Add removing GATT services Claudio Takahasi
                     ` (2 preceding siblings ...)
  2014-04-03 19:46   ` [PATCH BlueZ v1 3/3] doc: Add InvalidArguments to UnregisterService() errors Claudio Takahasi
@ 2014-04-04  7:30   ` Johan Hedberg
  3 siblings, 0 replies; 15+ messages in thread
From: Johan Hedberg @ 2014-04-04  7:30 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth

Hi Claudio,

On Thu, Apr 03, 2014, Claudio Takahasi wrote:
> This patchset implements GattManager1.UnregisterService(), and low-level
> functions to remove service declarations (and its attributes) from the
> attribute database.
> 
> Changes v1-v0:
>  * Fix potential invalid memory access
>  * Cleanup of external service when registration fails
> 
> Claudio Takahasi (3):
>   gatt: Add removing service from the database
>   gatt: Fix possibly lost block when bluetoothd exits
>   doc: Add InvalidArguments to UnregisterService() errors
> 
>  doc/gatt-api.txt |  3 ++-
>  src/gatt-dbus.c  | 51 +++++++++++++++++++++++++++++++++++++++++----------
>  2 files changed, 43 insertions(+), 11 deletions(-)

All three patches have been applied. Thanks.

Johan

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2014-04-04  7:30 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-02 18:30 [PATCH BlueZ v0 0/7] Add removing GATT services Claudio Takahasi
2014-04-02 18:30 ` [PATCH BlueZ v0 1/7] gatt: Add helper for " Claudio Takahasi
2014-04-02 18:30 ` [PATCH BlueZ v0 2/7] gdbus: Avoid reporting GDBusClient disconnect twice Claudio Takahasi
2014-04-02 18:30 ` [PATCH BlueZ v0 3/7] gatt: Rename external_app to external_service Claudio Takahasi
2014-04-02 18:30 ` [PATCH BlueZ v0 4/7] gatt: Add GattManager1.UnregisterService() Claudio Takahasi
2014-04-02 18:30 ` [PATCH BlueZ v0 5/7] gatt: Add removing service from the database Claudio Takahasi
2014-04-03  7:49   ` Johan Hedberg
2014-04-03 19:12     ` Claudio Takahasi
2014-04-02 18:30 ` [PATCH BlueZ v0 6/7] gatt: Fix possibly lost block when bluetoothd exits Claudio Takahasi
2014-04-02 18:30 ` [PATCH BlueZ v0 7/7] doc: Add InvalidArguments to UnregisterService() errors Claudio Takahasi
2014-04-03 19:46 ` [PATCH BlueZ v1 0/3] Add removing GATT services Claudio Takahasi
2014-04-03 19:46   ` [PATCH BlueZ v1 1/3] gatt: Add removing service from the database Claudio Takahasi
2014-04-03 19:46   ` [PATCH BlueZ v1 2/3] gatt: Fix possibly lost block when bluetoothd exits Claudio Takahasi
2014-04-03 19:46   ` [PATCH BlueZ v1 3/3] doc: Add InvalidArguments to UnregisterService() errors Claudio Takahasi
2014-04-04  7:30   ` [PATCH BlueZ v1 0/3] Add removing GATT services Johan Hedberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).