All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify
@ 2017-07-04 15:09 Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 01/10] doc/gatt-api: " Luiz Augusto von Dentz
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This set adds 2 new methods to GattCharacteristics1, thse deal with
attributes that attempts to emulate a byte stream transfer, or a protocol
on top of GATT, using write without response and notifications.

v2:
- Rename WriteLocked and NotifyLocked to WriteAcquired and NotifyAcquired
- Make WriteAcquired and NotifyAcquired optional so they only appear if
the required flags are supported.
- Make sure O_CLOEXEC and O_NONBLOCK are set in the flags passed to pipe2.

Luiz Augusto von Dentz (10):
  doc/gatt-api: Add AcquireWrite and AcquireNotify
  shared/gatt-client: Allow multiple ready callbacks
  gatt: Add implementation of AcquireWrite
  gatt: Add implementation of WriteAcquired
  client: Add acquire-write command
  client: Add release-write command
  gatt: Add implementation of AcquireNotify
  gatt: Add implementation of NotifyAcquired
  client: Add acquire-notify command
  client: Add release-notify command

 Makefile.tools           |   4 +-
 client/gatt.c            | 209 +++++++++++++++++++++++++++
 client/gatt.h            |   6 +
 client/main.c            |  48 +++++++
 doc/gatt-api.txt         |  62 ++++++++
 peripheral/gatt.c        |   4 +-
 src/device.c             |  16 ++-
 src/gatt-client.c        | 367 +++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/gatt-client.c |  60 ++++++--
 src/shared/gatt-client.h |   4 +-
 tools/btgatt-client.c    |   2 +-
 unit/test-gatt.c         |   4 +-
 12 files changed, 759 insertions(+), 27 deletions(-)

-- 
2.9.4


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

* [PATCH v2 01/10] doc/gatt-api: Add AcquireWrite and AcquireNotify
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 16:01   ` Marcel Holtmann
  2017-07-04 15:09 ` [PATCH v2 02/10] shared/gatt-client: Allow multiple ready callbacks Luiz Augusto von Dentz
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This enables write and notify exclusive access via file descriptors in
case the characteristic is actually trying to emulate a byte stream
transfer or have a protocol on top of GATT.
---
 doc/gatt-api.txt | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index 6c98b87..3f4a3ca 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -91,6 +91,56 @@ Methods		array{byte} ReadValue(dict options)
 					 org.bluez.Error.NotAuthorized
 					 org.bluez.Error.NotSupported
 
+		fd, uint16 AcquireWrite() [experimental] (Client only)
+
+			Acquire write file descriptor and MTU and lock
+			write access to the characteristic.
+
+			Only works with characteristic that has
+			WriteAcquired property which relies on
+			write-without-response Flag.
+
+			To release the lock the client shall close the file
+			descriptor, a HUP is generated in case the device
+			is disconnected.
+
+			Note: the MTU can only be negotiated once and is
+			symmetric therefore this method may be delayed in
+			order to have the exchange MTU completed, because of
+			that the file descriptor is closed during
+			reconnections as the MTU has to be renegotiated.
+
+			Possible Errors: org.bluez.Error.Failed
+					 org.bluez.Error.NotSupported
+
+		fd, uint16 AcquireNotify() [experimental] (Client only)
+
+			Acquire notify file descriptor and MTU and lock
+			notifications to the characteristic.
+
+			Only works with characteristic that has NotifyAcquired
+			which relies on notify Flag and no other client have
+			called StartNotify.
+
+			Notification are enabled during this procedure so
+			StartNotify shall not be called, any notification
+			will be dispatched via file descriptor therefore the
+			Value property is no affected during the time where
+			notify has been acquired.
+
+			To release the lock the client shall close the file
+			descriptor, a HUP is generated in case the device
+			is disconnected.
+
+			Note: the MTU can only be negotiated once and is
+			symmetric therefore this method may be delayed in
+			order to have the exchange MTU completed, because of
+			that the file descriptor is closed during
+			reconnections as the MTU has to be renegotiated.
+
+			Possible Errors: org.bluez.Error.Failed
+					 org.bluez.Error.NotSupported
+
 		void StartNotify()
 
 			Starts a notification session from this characteristic
@@ -125,6 +175,18 @@ Properties	string UUID [read-only]
 			when a notification or indication is received, upon
 			which a PropertiesChanged signal will be emitted.
 
+		boolean WriteAcquired [read-only, optional]
+
+			True, if this characteristic has been acquire by any
+			client using AcquireWrite. This properties is ommited
+			in case write-without-response flag is not set.
+
+		boolean NotifyAcquired [read-only, optional]
+
+			True, if this characteristic has been acquire by any
+			client using AcquireNotify. This properties is ommited
+			in case notify flag is not set.
+
 		boolean Notifying [read-only, optional]
 
 			True, if notifications or indications on this
-- 
2.9.4


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

* [PATCH v2 02/10] shared/gatt-client: Allow multiple ready callbacks
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 01/10] doc/gatt-api: " Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 03/10] gatt: Add implementation of AcquireWrite Luiz Augusto von Dentz
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This makes the ready callbacks much more convenient to track when the
client is ready since its is now possible to notify more than on client
at the same time.
---
 peripheral/gatt.c        |  4 ++--
 src/device.c             | 10 ++++----
 src/shared/gatt-client.c | 60 ++++++++++++++++++++++++++++++++++++------------
 src/shared/gatt-client.h |  4 +++-
 tools/btgatt-client.c    |  2 +-
 unit/test-gatt.c         |  4 ++--
 6 files changed, 59 insertions(+), 25 deletions(-)

diff --git a/peripheral/gatt.c b/peripheral/gatt.c
index 4c5531d..5ae19a8 100644
--- a/peripheral/gatt.c
+++ b/peripheral/gatt.c
@@ -145,8 +145,8 @@ static struct gatt_conn *gatt_conn_new(int fd)
 		return NULL;
 	}
 
-	bt_gatt_client_set_ready_handler(conn->client,
-				client_ready_callback, conn, NULL);
+	bt_gatt_client_ready_register(conn->client, client_ready_callback,
+								conn, NULL);
 	bt_gatt_client_set_service_changed(conn->client,
 				client_service_changed_callback, conn, NULL);
 
diff --git a/src/device.c b/src/device.c
index def192f..8cb79df 100644
--- a/src/device.c
+++ b/src/device.c
@@ -226,6 +226,7 @@ struct btd_device {
 	struct gatt_db *db;			/* GATT db cache */
 	struct bt_gatt_client *client;		/* GATT client instance */
 	struct bt_gatt_server *server;		/* GATT server instance */
+	unsigned int gatt_ready_id;
 
 	struct btd_gatt_client *client_dbus;
 
@@ -550,7 +551,7 @@ static void gatt_client_cleanup(struct btd_device *device)
 
 	gatt_cache_cleanup(device);
 	bt_gatt_client_set_service_changed(device->client, NULL, NULL, NULL);
-	bt_gatt_client_set_ready_handler(device->client, NULL, NULL, NULL);
+	bt_gatt_client_ready_unregister(device->client, device->gatt_ready_id);
 	bt_gatt_client_unref(device->client);
 	device->client = NULL;
 }
@@ -4718,10 +4719,11 @@ static void gatt_client_init(struct btd_device *device)
 	 */
 	device_accept_gatt_profiles(device);
 
-	if (!bt_gatt_client_set_ready_handler(device->client,
+	device->gatt_ready_id = bt_gatt_client_ready_register(device->client,
 							gatt_client_ready_cb,
-							device, NULL)) {
-		DBG("Failed to set ready handler");
+							device, NULL);
+	if (!device->gatt_ready_id) {
+		DBG("Failed to register GATT ready callback");
 		gatt_client_cleanup(device);
 		return;
 	}
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index fbf90ff..a34b001 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -51,6 +51,12 @@
 #define GATT_SVC_UUID	0x1801
 #define SVC_CHNGD_UUID	0x2a05
 
+struct ready_cb {
+	bt_gatt_client_callback_t callback;
+	bt_gatt_client_destroy_func_t destroy;
+	void *data;
+};
+
 struct bt_gatt_client {
 	struct bt_att *att;
 	int ref_count;
@@ -58,9 +64,7 @@ struct bt_gatt_client {
 	struct bt_gatt_client *parent;
 	struct queue *clones;
 
-	bt_gatt_client_callback_t ready_callback;
-	bt_gatt_client_destroy_func_t ready_destroy;
-	void *ready_data;
+	struct queue *ready_cbs;
 
 	bt_gatt_client_service_changed_callback_t svc_chngd_callback;
 	bt_gatt_client_destroy_func_t svc_chngd_destroy;
@@ -1097,17 +1101,35 @@ done:
 	discovery_op_complete(op, success, att_ecode);
 }
 
+static void ready_destroy(void *data)
+{
+	struct ready_cb *ready = data;
+
+	if (ready->destroy)
+		ready->destroy(ready->data);
+
+	free(ready);
+}
+
 static void notify_client_ready(struct bt_gatt_client *client, bool success,
 							uint8_t att_ecode)
 {
 	const struct queue_entry *entry;
 
-	if (!client->ready_callback || client->ready)
+	if (client->ready)
 		return;
 
 	bt_gatt_client_ref(client);
 	client->ready = success;
-	client->ready_callback(success, att_ecode, client->ready_data);
+
+	for (entry = queue_get_entries(client->ready_cbs); entry;
+							entry = entry->next) {
+		struct ready_cb *ready = entry->data;
+
+		ready->callback(success, att_ecode, ready->data);
+	}
+
+	queue_remove_all(client->ready_cbs, NULL, NULL, ready_destroy);
 
 	/* Notify clones */
 	for (entry = queue_get_entries(client->clones); entry;
@@ -1731,8 +1753,7 @@ static void bt_gatt_client_free(struct bt_gatt_client *client)
 
 	queue_destroy(client->notify_list, notify_data_cleanup);
 
-	if (client->ready_destroy)
-		client->ready_destroy(client->ready_data);
+	queue_destroy(client->ready_cbs, ready_destroy);
 
 	if (client->debug_destroy)
 		client->debug_destroy(client->debug_data);
@@ -1789,6 +1810,7 @@ static struct bt_gatt_client *gatt_client_new(struct gatt_db *db,
 		goto fail;
 
 	client->clones = queue_new();
+	client->ready_cbs = queue_new();
 	client->long_write_queue = queue_new();
 	client->svc_chngd_queue = queue_new();
 	client->notify_list = queue_new();
@@ -1886,22 +1908,30 @@ bool bt_gatt_client_is_ready(struct bt_gatt_client *client)
 	return (client && client->ready);
 }
 
-bool bt_gatt_client_set_ready_handler(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_ready_register(struct bt_gatt_client *client,
 					bt_gatt_client_callback_t callback,
 					void *user_data,
 					bt_gatt_client_destroy_func_t destroy)
 {
+	struct ready_cb *ready;
+
 	if (!client)
-		return false;
+		return 0;
 
-	if (client->ready_destroy)
-		client->ready_destroy(client->ready_data);
+	ready = new0(struct ready_cb, 1);
+	ready->callback = callback;
+	ready->destroy = destroy;
+	ready->data = user_data;
 
-	client->ready_callback = callback;
-	client->ready_destroy = destroy;
-	client->ready_data = user_data;
+	queue_push_tail(client->ready_cbs, ready);
 
-	return true;
+	return PTR_TO_UINT(ready);
+}
+
+bool bt_gatt_client_ready_unregister(struct bt_gatt_client *client,
+						unsigned int id)
+{
+	return queue_remove(client->ready_cbs, UINT_TO_PTR(id));
 }
 
 bool bt_gatt_client_set_service_changed(struct bt_gatt_client *client,
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index aceb570..6d8bf80 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -57,10 +57,12 @@ typedef void (*bt_gatt_client_service_changed_callback_t)(uint16_t start_handle,
 							void *user_data);
 
 bool bt_gatt_client_is_ready(struct bt_gatt_client *client);
-bool bt_gatt_client_set_ready_handler(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_ready_register(struct bt_gatt_client *client,
 					bt_gatt_client_callback_t callback,
 					void *user_data,
 					bt_gatt_client_destroy_func_t destroy);
+bool bt_gatt_client_ready_unregister(struct bt_gatt_client *client,
+						unsigned int id);
 bool bt_gatt_client_set_service_changed(struct bt_gatt_client *client,
 			bt_gatt_client_service_changed_callback_t callback,
 			void *user_data,
diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index f97963e..51bc362 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -235,7 +235,7 @@ static struct client *client_create(int fd, uint16_t mtu)
 									NULL);
 	}
 
-	bt_gatt_client_set_ready_handler(cli->gatt, ready_cb, cli, NULL);
+	bt_gatt_client_ready_register(cli->gatt, ready_cb, cli, NULL);
 	bt_gatt_client_set_service_changed(cli->gatt, service_changed_cb, cli,
 									NULL);
 
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 15638dc..5d79e94 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -684,8 +684,8 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
 		bt_gatt_client_set_debug(context->client, print_debug,
 						"bt_gatt_client:", NULL);
 
-		bt_gatt_client_set_ready_handler(context->client,
-						client_ready_cb, context, NULL);
+		bt_gatt_client_ready_register(context->client, client_ready_cb,
+								context, NULL);
 		break;
 	default:
 		break;
-- 
2.9.4


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

* [PATCH v2 03/10] gatt: Add implementation of AcquireWrite
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 01/10] doc/gatt-api: " Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 02/10] shared/gatt-client: Allow multiple ready callbacks Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 04/10] gatt: Add implementation of WriteAcquired Luiz Augusto von Dentz
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This implements AcquireWrite creating a pipe and passing the write fd
to the application requesting it:

bluetoothd[29915]: src/gatt-client.c:characteristic_create_pipe() AcquireWrite: sender :1.378 io 0x89cdfe0

The fd is monitored and in case the client decides close it, or exit/crash,
the daemon detects the HUP and cleanup properly:

bluetoothd[29915]: src/gatt-client.c:characteristic_pipe_hup() /org/bluez/hci1/dev_00_1B_DC_07_31_88/service001f/char0020: io 0x89cdfe0
---
 src/device.c      |   8 ++-
 src/gatt-client.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+), 1 deletion(-)

diff --git a/src/device.c b/src/device.c
index 8cb79df..6a9936a 100644
--- a/src/device.c
+++ b/src/device.c
@@ -551,7 +551,13 @@ static void gatt_client_cleanup(struct btd_device *device)
 
 	gatt_cache_cleanup(device);
 	bt_gatt_client_set_service_changed(device->client, NULL, NULL, NULL);
-	bt_gatt_client_ready_unregister(device->client, device->gatt_ready_id);
+
+	if (device->gatt_ready_id > 0) {
+		bt_gatt_client_ready_unregister(device->client,
+						device->gatt_ready_id);
+		device->gatt_ready_id = 0;
+	}
+
 	bt_gatt_client_unref(device->client);
 	device->client = NULL;
 }
diff --git a/src/gatt-client.c b/src/gatt-client.c
index 6c67841..9a660df 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -24,6 +24,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
 
 #include <dbus/dbus.h>
 
@@ -37,6 +39,7 @@
 #include "error.h"
 #include "adapter.h"
 #include "device.h"
+#include "src/shared/io.h"
 #include "src/shared/queue.h"
 #include "src/shared/att.h"
 #include "src/shared/gatt-db.h"
@@ -97,6 +100,10 @@ struct characteristic {
 	bt_uuid_t uuid;
 	char *path;
 
+	unsigned int ready_id;
+	DBusMessage *acquire_write;
+	struct io *write_io;
+
 	struct async_dbus_op *read_op;
 	struct async_dbus_op *write_op;
 
@@ -990,6 +997,151 @@ fail:
 	return btd_error_not_supported(msg);
 }
 
+static bool chrc_pipe_read(struct io *io, void *user_data)
+{
+	struct characteristic *chrc = user_data;
+	struct bt_gatt_client *gatt = chrc->service->client->gatt;
+	uint8_t buf[512];
+	int fd = io_get_fd(io);
+	ssize_t bytes_read;
+
+	bytes_read = read(fd, buf, sizeof(buf));
+	if (bytes_read < 0)
+		return false;
+
+	if (!gatt)
+		return false;
+
+	bt_gatt_client_write_without_response(gatt, chrc->value_handle,
+					chrc->props & BT_GATT_CHRC_PROP_AUTH,
+					buf, bytes_read);
+
+	return true;
+}
+
+static void characteristic_destroy_pipe(struct characteristic *chrc,
+							struct io *io)
+{
+	if (io == chrc->write_io) {
+		io_destroy(chrc->write_io);
+		chrc->write_io = NULL;
+	}
+}
+
+static bool characteristic_pipe_hup(struct io *io, void *user_data)
+{
+	struct characteristic *chrc = user_data;
+
+	DBG("%s: io %p", chrc->path, io);
+
+	characteristic_destroy_pipe(chrc, io);
+
+	return false;
+}
+
+static DBusMessage *characteristic_create_pipe(struct characteristic *chrc,
+						DBusMessage *msg)
+{
+	struct bt_gatt_client *gatt = chrc->service->client->gatt;
+	int pipefd[2];
+	struct io *io;
+	bool dir;
+	uint16_t mtu;
+	DBusMessage *reply;
+
+	if (!gatt || !bt_gatt_client_is_ready(gatt))
+		return btd_error_failed(msg, "Not connected");
+
+	if (pipe2(pipefd, O_DIRECT | O_NONBLOCK | O_CLOEXEC) < 0)
+		return btd_error_failed(msg, strerror(errno));
+
+	dir = dbus_message_has_member(msg, "AcquireWrite");
+
+	io = io_new(pipefd[!dir]);
+	if (!io) {
+		close(pipefd[0]);
+		close(pipefd[1]);
+		return btd_error_failed(msg, strerror(EIO));
+	}
+
+	io_set_close_on_destroy(io, true);
+
+	if (!io_set_read_handler(io, chrc_pipe_read, chrc, NULL))
+		goto fail;
+
+	if (!io_set_disconnect_handler(io, characteristic_pipe_hup, chrc, NULL))
+		goto fail;
+
+	mtu = bt_gatt_client_get_mtu(gatt);
+
+	reply = g_dbus_create_reply(msg, DBUS_TYPE_UNIX_FD, &pipefd[dir],
+					DBUS_TYPE_UINT16, &mtu,
+					DBUS_TYPE_INVALID);
+
+	close(pipefd[dir]);
+
+	if (dir)
+		chrc->write_io = io;
+
+	DBG("%s: sender %s io %p", dbus_message_get_member(msg),
+					dbus_message_get_sender(msg), io);
+
+	return reply;
+
+fail:
+	io_destroy(io);
+	close(pipefd[dir]);
+	return btd_error_failed(msg, strerror(EIO));
+}
+
+static void characteristic_ready(bool success, uint8_t ecode, void *user_data)
+{
+	struct characteristic *chrc = user_data;
+	DBusMessage *reply;
+
+	chrc->ready_id = 0;
+
+	if (chrc->acquire_write) {
+		reply = characteristic_create_pipe(chrc, chrc->acquire_write);
+
+		g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+		dbus_message_unref(chrc->acquire_write);
+		chrc->acquire_write = NULL;
+	}
+}
+
+static DBusMessage *characteristic_acquire_write(DBusConnection *conn,
+					DBusMessage *msg, void *user_data)
+{
+	struct characteristic *chrc = user_data;
+	struct bt_gatt_client *gatt = chrc->service->client->gatt;
+
+	if (!gatt)
+		return btd_error_failed(msg, "Not connected");
+
+	if (chrc->write_io || chrc->acquire_write)
+		return btd_error_failed(msg, strerror(EBUSY));
+
+	if (chrc->write_op)
+		return btd_error_in_progress(msg);
+
+	if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
+		return btd_error_not_supported(msg);
+
+	if (!bt_gatt_client_is_ready(gatt)) {
+		DBG("GATT not ready, wait until it becomes read");
+		if (!chrc->ready_id)
+			chrc->ready_id = bt_gatt_client_ready_register(gatt,
+							characteristic_ready,
+							chrc, NULL);
+		chrc->acquire_write = dbus_message_ref(msg);
+		return NULL;
+	}
+
+	return characteristic_create_pipe(chrc, msg);
+}
+
 struct notify_client {
 	struct characteristic *chrc;
 	int ref_count;
@@ -1265,6 +1417,10 @@ static const GDBusMethodTable characteristic_methods[] = {
 						{ "options", "a{sv}" }),
 					NULL,
 					characteristic_write_value) },
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("AcquireWrite", NULL,
+					GDBUS_ARGS({ "fd", "h" },
+						{ "mtu", "q" }),
+					characteristic_acquire_write) },
 	{ GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL,
 					characteristic_start_notify) },
 	{ GDBUS_METHOD("StopNotify", NULL, NULL,
@@ -1280,6 +1436,11 @@ static void characteristic_free(void *data)
 	queue_destroy(chrc->descs, NULL);
 	queue_destroy(chrc->notify_clients, NULL);
 
+	io_destroy(chrc->write_io);
+
+	if (chrc->acquire_write)
+		dbus_message_unref(chrc->acquire_write);
+
 	g_free(chrc->path);
 	free(chrc);
 }
-- 
2.9.4


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

* [PATCH v2 04/10] gatt: Add implementation of WriteAcquired
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 03/10] gatt: Add implementation of AcquireWrite Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 05/10] client: Add acquire-write command Luiz Augusto von Dentz
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This property indicate if any client has acquire write thus locking the
access to WriteValue.
---
 src/gatt-client.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/src/gatt-client.c b/src/gatt-client.c
index 9a660df..9ab5f96 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -818,6 +818,27 @@ static gboolean characteristic_get_flags(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static gboolean
+characteristic_get_write_acquired(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct characteristic *chrc = data;
+	dbus_bool_t locked = chrc->write_io ? TRUE : FALSE;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &locked);
+
+	return TRUE;
+}
+
+static gboolean
+characteristic_write_acquired_exists(const GDBusPropertyTable *property,
+								void *data)
+{
+	struct characteristic *chrc = data;
+
+	return (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP);
+}
+
 static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
 								void *user_data)
 {
@@ -1025,6 +1046,10 @@ static void characteristic_destroy_pipe(struct characteristic *chrc,
 	if (io == chrc->write_io) {
 		io_destroy(chrc->write_io);
 		chrc->write_io = NULL;
+		g_dbus_emit_property_changed(btd_get_dbus_connection(),
+						chrc->path,
+						GATT_CHARACTERISTIC_IFACE,
+						"WriteAcquired");
 	}
 }
 
@@ -1080,8 +1105,13 @@ static DBusMessage *characteristic_create_pipe(struct characteristic *chrc,
 
 	close(pipefd[dir]);
 
-	if (dir)
+	if (dir) {
 		chrc->write_io = io;
+		g_dbus_emit_property_changed(btd_get_dbus_connection(),
+						chrc->path,
+						GATT_CHARACTERISTIC_IFACE,
+						"WriteAcquired");
+	}
 
 	DBG("%s: sender %s io %p", dbus_message_get_member(msg),
 					dbus_message_get_sender(msg), io);
@@ -1406,6 +1436,9 @@ static const GDBusPropertyTable characteristic_properties[] = {
 	{ "Notifying", "b", characteristic_get_notifying, NULL,
 					characteristic_notifying_exists },
 	{ "Flags", "as", characteristic_get_flags, NULL, NULL },
+	{ "WriteAcquired", "b", characteristic_get_write_acquired, NULL,
+				characteristic_write_acquired_exists,
+				G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
 	{ }
 };
 
-- 
2.9.4


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

* [PATCH v2 05/10] client: Add acquire-write command
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 04/10] gatt: Add implementation of WriteAcquired Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 06/10] client: Add release-write command Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds acquire-write command which uses D-Bus AcquireWrite methods
to acquire a file descriptor to write to locking the attribute:

[Test peripheral:/service001f/char0020]# acquire-write
[CHG] Attribute /org/bluez/hci1/dev_00_1B_DC_07_31_88/service001f/char0020 WriteAcquired: yes
AcquireWrite success: fd 7 MTU 65
[Test peripheral:/service001f/char0020]# write 00
Attempting to write fd 7

< ACL Data TX: Handle 3585 flags 0x00 dlen 8
      ATT: Write Command (0x52) len 3
        Handle: 0x0021
          Data: 00
---
 client/gatt.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 client/gatt.h |  2 ++
 client/main.c | 12 ++++++++++
 3 files changed, 87 insertions(+)

diff --git a/client/gatt.c b/client/gatt.c
index 8a4491a..e6f37ae 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -89,6 +89,10 @@ static GList *descriptors;
 static GList *managers;
 static GList *uuids;
 
+static GDBusProxy *write_proxy;
+static int write_fd = -1;
+static uint16_t write_mtu;
+
 static void print_service(struct service *service, const char *description)
 {
 	const char *text;
@@ -236,6 +240,15 @@ void gatt_remove_characteristic(GDBusProxy *proxy)
 	characteristics = g_list_delete_link(characteristics, l);
 
 	print_characteristic(proxy, COLORED_DEL);
+
+	if (write_proxy == proxy) {
+		write_proxy = NULL;
+		write_mtu = 0;
+		if (write_fd > 0) {
+			close(write_fd);
+			write_fd = -1;
+		}
+	}
 }
 
 static void print_desc(struct desc *desc, const char *description)
@@ -619,6 +632,16 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
 	iov.iov_base = value;
 	iov.iov_len = i;
 
+	/* Write using the fd if it has been acquired and fit the MTU */
+	if (proxy == write_proxy && (write_fd > 0 && write_mtu >= i)) {
+		rl_printf("Attempting to write fd %d\n", write_fd);
+		if (writev(write_fd, &iov, 1) < 0) {
+			rl_printf("Failed to write: %s", strerror(errno));
+			return;
+		}
+		return;
+	}
+
 	if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
 					write_reply, &iov, NULL) == FALSE) {
 		rl_printf("Failed to write\n");
@@ -643,6 +666,56 @@ void gatt_write_attribute(GDBusProxy *proxy, const char *arg)
 						g_dbus_proxy_get_path(proxy));
 }
 
+static void acquire_write_reply(DBusMessage *message, void *user_data)
+{
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, message) == TRUE) {
+		rl_printf("Failed to acquire write: %s\n", error.name);
+		dbus_error_free(&error);
+		write_proxy = NULL;
+		return;
+	}
+
+	if (write_fd > 0) {
+		close(write_fd);
+		write_fd = -1;
+	}
+
+	write_mtu = 0;
+
+	if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &write_fd,
+					DBUS_TYPE_UINT16, &write_mtu,
+					DBUS_TYPE_INVALID) == false)) {
+		rl_printf("Invalid AcquireWrite response\n");
+		return;
+	}
+
+	rl_printf("AcquireWrite success: fd %d MTU %u\n", write_fd, write_mtu);
+}
+
+void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
+{
+	const char *iface;
+
+	iface = g_dbus_proxy_get_interface(proxy);
+	if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
+		rl_printf("Unable to acquire write: %s not a characteristic\n",
+						g_dbus_proxy_get_path(proxy));
+		return;
+	}
+
+	if (g_dbus_proxy_method_call(proxy, "AcquireWrite", NULL,
+				acquire_write_reply, NULL, NULL) == FALSE) {
+		rl_printf("Failed to AcquireWrite\n");
+		return;
+	}
+
+	write_proxy = proxy;
+}
+
 static void notify_reply(DBusMessage *message, void *user_data)
 {
 	bool enable = GPOINTER_TO_UINT(user_data);
diff --git a/client/gatt.h b/client/gatt.h
index 8031a46..713d34f 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -38,6 +38,8 @@ void gatt_read_attribute(GDBusProxy *proxy);
 void gatt_write_attribute(GDBusProxy *proxy, const char *arg);
 void gatt_notify_attribute(GDBusProxy *proxy, bool enable);
 
+void gatt_acquire_write(GDBusProxy *proxy, const char *arg);
+
 void gatt_add_manager(GDBusProxy *proxy);
 void gatt_remove_manager(GDBusProxy *proxy);
 
diff --git a/client/main.c b/client/main.c
index 3af533e..79f61a1 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1799,6 +1799,16 @@ static void cmd_write(const char *arg)
 	gatt_write_attribute(default_attr, arg);
 }
 
+static void cmd_acquire_write(const char *arg)
+{
+	if (!default_attr) {
+		rl_printf("No attribute selected\n");
+		return;
+	}
+
+	gatt_acquire_write(default_attr, arg);
+}
+
 static void cmd_notify(const char *arg)
 {
 	dbus_bool_t enable;
@@ -2274,6 +2284,8 @@ static const struct {
 	{ "read",         NULL,       cmd_read, "Read attribute value" },
 	{ "write",        "<data=[xx xx ...]>", cmd_write,
 						"Write attribute value" },
+	{ "acquire-write", NULL, cmd_acquire_write,
+					"Acquire Write file descriptor" },
 	{ "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
 	{ "register-application", "[UUID ...]", cmd_register_app,
 						"Register profile to connect" },
-- 
2.9.4


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

* [PATCH v2 06/10] client: Add release-write command
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 05/10] client: Add acquire-write command Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 07/10] gatt: Add implementation of AcquireNotify Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds release-write command which closes an existing fd unlocking
the attribute:

[Test peripheral:/service001f/char0020]# release-write
[CHG] Attribute /org/bluez/hci1/dev_00_1B_DC_07_31_88/service001f/char0020 WriteAcquired: no
---
 client/gatt.c | 13 +++++++++++++
 client/gatt.h |  1 +
 client/main.c | 12 ++++++++++++
 3 files changed, 26 insertions(+)

diff --git a/client/gatt.c b/client/gatt.c
index e6f37ae..2756efd 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -716,6 +716,19 @@ void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
 	write_proxy = proxy;
 }
 
+void gatt_release_write(GDBusProxy *proxy, const char *arg)
+{
+	if (proxy != write_proxy || write_fd < 0) {
+		rl_printf("Write not acquired\n");
+		return;
+	}
+
+	write_proxy = NULL;
+	close(write_fd);
+	write_fd = -1;
+	write_mtu = 0;
+}
+
 static void notify_reply(DBusMessage *message, void *user_data)
 {
 	bool enable = GPOINTER_TO_UINT(user_data);
diff --git a/client/gatt.h b/client/gatt.h
index 713d34f..6827057 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -39,6 +39,7 @@ void gatt_write_attribute(GDBusProxy *proxy, const char *arg);
 void gatt_notify_attribute(GDBusProxy *proxy, bool enable);
 
 void gatt_acquire_write(GDBusProxy *proxy, const char *arg);
+void gatt_release_write(GDBusProxy *proxy, const char *arg);
 
 void gatt_add_manager(GDBusProxy *proxy);
 void gatt_remove_manager(GDBusProxy *proxy);
diff --git a/client/main.c b/client/main.c
index 79f61a1..7688a23 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1809,6 +1809,16 @@ static void cmd_acquire_write(const char *arg)
 	gatt_acquire_write(default_attr, arg);
 }
 
+static void cmd_release_write(const char *arg)
+{
+	if (!default_attr) {
+		rl_printf("No attribute selected\n");
+		return;
+	}
+
+	gatt_release_write(default_attr, arg);
+}
+
 static void cmd_notify(const char *arg)
 {
 	dbus_bool_t enable;
@@ -2286,6 +2296,8 @@ static const struct {
 						"Write attribute value" },
 	{ "acquire-write", NULL, cmd_acquire_write,
 					"Acquire Write file descriptor" },
+	{ "release-write", NULL, cmd_release_write,
+					"Release Write file descriptor" },
 	{ "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
 	{ "register-application", "[UUID ...]", cmd_register_app,
 						"Register profile to connect" },
-- 
2.9.4


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

* [PATCH v2 07/10] gatt: Add implementation of AcquireNotify
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 06/10] client: Add release-write command Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 08/10] gatt: Add implementation of NotifyAcquired Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This implements AcquireNotify creating a pipe and passing the read fd
to the application requesting it, at same time subscribe for
notifications:

bluetoothd[7279]: src/gatt-client.c:notify_client_ref() owner :1.461
bluetoothd[7279]: src/gatt-client.c:characteristic_create_pipe() AcquireNotify: sender :1.461 io 0x8a60540
---
 src/gatt-client.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 155 insertions(+), 15 deletions(-)

diff --git a/src/gatt-client.c b/src/gatt-client.c
index 9ab5f96..571d310 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -89,6 +89,13 @@ struct async_dbus_op {
 	async_dbus_op_complete_t complete;
 };
 
+struct pipe_io {
+	DBusMessage *msg;
+	struct io *io;
+	void (*destroy)(void *data);
+	void *data;
+};
+
 struct characteristic {
 	struct service *service;
 	struct gatt_db_attribute *attr;
@@ -101,8 +108,8 @@ struct characteristic {
 	char *path;
 
 	unsigned int ready_id;
-	DBusMessage *acquire_write;
-	struct io *write_io;
+	struct pipe_io *write_io;
+	struct pipe_io *notify_io;
 
 	struct async_dbus_op *read_op;
 	struct async_dbus_op *write_op;
@@ -1040,16 +1047,31 @@ static bool chrc_pipe_read(struct io *io, void *user_data)
 	return true;
 }
 
+static void pipe_io_destroy(struct pipe_io *io)
+{
+	if (io->destroy)
+		io->destroy(io->data);
+
+	if (io->msg)
+		dbus_message_unref(io->msg);
+
+	io_destroy(io->io);
+	free(io);
+}
+
 static void characteristic_destroy_pipe(struct characteristic *chrc,
 							struct io *io)
 {
-	if (io == chrc->write_io) {
-		io_destroy(chrc->write_io);
+	if (chrc->write_io && io == chrc->write_io->io) {
+		pipe_io_destroy(chrc->write_io);
 		chrc->write_io = NULL;
 		g_dbus_emit_property_changed(btd_get_dbus_connection(),
 						chrc->path,
 						GATT_CHARACTERISTIC_IFACE,
 						"WriteAcquired");
+	} else if (chrc->notify_io) {
+		pipe_io_destroy(chrc->notify_io);
+		chrc->notify_io = NULL;
 	}
 }
 
@@ -1106,12 +1128,13 @@ static DBusMessage *characteristic_create_pipe(struct characteristic *chrc,
 	close(pipefd[dir]);
 
 	if (dir) {
-		chrc->write_io = io;
+		chrc->write_io->io = io;
 		g_dbus_emit_property_changed(btd_get_dbus_connection(),
 						chrc->path,
 						GATT_CHARACTERISTIC_IFACE,
 						"WriteAcquired");
-	}
+	} else
+		chrc->notify_io->io = io;
 
 	DBG("%s: sender %s io %p", dbus_message_get_member(msg),
 					dbus_message_get_sender(msg), io);
@@ -1131,13 +1154,22 @@ static void characteristic_ready(bool success, uint8_t ecode, void *user_data)
 
 	chrc->ready_id = 0;
 
-	if (chrc->acquire_write) {
-		reply = characteristic_create_pipe(chrc, chrc->acquire_write);
+	if (chrc->write_io->msg) {
+		reply = characteristic_create_pipe(chrc, chrc->write_io->msg);
 
 		g_dbus_send_message(btd_get_dbus_connection(), reply);
 
-		dbus_message_unref(chrc->acquire_write);
-		chrc->acquire_write = NULL;
+		dbus_message_unref(chrc->write_io->msg);
+		chrc->write_io->msg = NULL;
+	}
+
+	if (chrc->notify_io->msg) {
+		reply = characteristic_create_pipe(chrc, chrc->notify_io->msg);
+
+		g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+		dbus_message_unref(chrc->notify_io->msg);
+		chrc->notify_io->msg = NULL;
 	}
 }
 
@@ -1150,7 +1182,7 @@ static DBusMessage *characteristic_acquire_write(DBusConnection *conn,
 	if (!gatt)
 		return btd_error_failed(msg, "Not connected");
 
-	if (chrc->write_io || chrc->acquire_write)
+	if (chrc->write_io)
 		return btd_error_failed(msg, strerror(EBUSY));
 
 	if (chrc->write_op)
@@ -1159,13 +1191,15 @@ static DBusMessage *characteristic_acquire_write(DBusConnection *conn,
 	if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
 		return btd_error_not_supported(msg);
 
+	chrc->write_io = new0(struct pipe_io, 1);
+
 	if (!bt_gatt_client_is_ready(gatt)) {
 		DBG("GATT not ready, wait until it becomes read");
 		if (!chrc->ready_id)
 			chrc->ready_id = bt_gatt_client_ready_register(gatt,
 							characteristic_ready,
 							chrc, NULL);
-		chrc->acquire_write = dbus_message_ref(msg);
+		chrc->write_io->msg = dbus_message_ref(msg);
 		return NULL;
 	}
 
@@ -1338,6 +1372,98 @@ static void register_notify_cb(uint16_t att_ecode, void *user_data)
 	create_notify_reply(op, true, 0);
 }
 
+static void notify_io_cb(uint16_t value_handle, const uint8_t *value,
+					uint16_t length, void *user_data)
+{
+	struct iovec iov;
+	struct notify_client *client = user_data;
+	struct characteristic *chrc = client->chrc;
+	int err;
+
+	/* Drop notification if the pipe is not ready */
+	if (!chrc->notify_io->io)
+		return;
+
+	iov.iov_base = (void *) value;
+	iov.iov_len = length;
+
+	err = io_send(chrc->notify_io->io, &iov, 1);
+	if (err < 0)
+		error("io_send: %s", strerror(-err));
+}
+
+static void register_notify_io_cb(uint16_t att_ecode, void *user_data)
+{
+	struct notify_client *client = user_data;
+	struct characteristic *chrc = client->chrc;
+
+	if (!att_ecode)
+		return;
+
+	queue_remove(chrc->notify_clients, client);
+	notify_client_free(client);
+
+	pipe_io_destroy(chrc->notify_io);
+	chrc->notify_io = NULL;
+}
+
+static void notify_io_destroy(void *data)
+{
+	struct notify_client *client = data;
+
+	queue_remove(client->chrc->notify_clients, client);
+	notify_client_unref(client);
+}
+
+static DBusMessage *characteristic_acquire_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 notify_client *client;
+
+	if (!gatt)
+		return btd_error_failed(msg, "Not connected");
+
+	/* Each client can only have one active notify session. */
+	if (chrc->notify_io || !queue_isempty(chrc->notify_clients))
+		return btd_error_failed(msg, strerror(EBUSY));
+
+	if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
+				chrc->props & BT_GATT_CHRC_PROP_INDICATE))
+		return btd_error_not_supported(msg);
+
+	client = notify_client_create(chrc, sender);
+	if (!client)
+		return btd_error_failed(msg, "Failed allocate notify session");
+
+	client->notify_id = bt_gatt_client_register_notify(gatt,
+						chrc->value_handle,
+						register_notify_io_cb,
+						notify_io_cb,
+						client, NULL);
+	if (!client->notify_id)
+		return btd_error_failed(msg, "Failed to subscribe");
+
+	queue_push_tail(chrc->notify_clients, client);
+
+	chrc->notify_io = new0(struct pipe_io, 1);
+	chrc->notify_io->data = client;
+	chrc->notify_io->destroy = notify_io_destroy;
+
+	if (!bt_gatt_client_is_ready(gatt)) {
+		if (!chrc->ready_id)
+			chrc->ready_id = bt_gatt_client_ready_register(gatt,
+							characteristic_ready,
+							chrc, NULL);
+		chrc->notify_io->msg = dbus_message_ref(msg);
+		return NULL;
+	}
+
+	return characteristic_create_pipe(chrc, msg);
+}
+
 static DBusMessage *characteristic_start_notify(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
@@ -1347,6 +1473,9 @@ static DBusMessage *characteristic_start_notify(DBusConnection *conn,
 	struct async_dbus_op *op;
 	struct notify_client *client;
 
+	if (chrc->notify_io)
+		return btd_error_failed(msg, strerror(EBUSY));
+
 	if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
 				chrc->props & BT_GATT_CHRC_PROP_INDICATE))
 		return btd_error_not_supported(msg);
@@ -1419,6 +1548,12 @@ static DBusMessage *characteristic_stop_notify(DBusConnection *conn,
 	if (!client)
 		return btd_error_failed(msg, "No notify session started");
 
+	if (chrc->notify_io) {
+		pipe_io_destroy(chrc->notify_io);
+		chrc->notify_io = NULL;
+		return dbus_message_new_method_return(msg);
+	}
+
 	queue_remove(chrc->service->client->all_notify_clients, client);
 	bt_gatt_client_unregister_notify(gatt, client->notify_id);
 	update_notifying(chrc);
@@ -1454,6 +1589,10 @@ static const GDBusMethodTable characteristic_methods[] = {
 					GDBUS_ARGS({ "fd", "h" },
 						{ "mtu", "q" }),
 					characteristic_acquire_write) },
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("AcquireNotify", NULL,
+					GDBUS_ARGS({ "fd", "h" },
+						{ "mtu", "q" }),
+					characteristic_acquire_notify) },
 	{ GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL,
 					characteristic_start_notify) },
 	{ GDBUS_METHOD("StopNotify", NULL, NULL,
@@ -1469,10 +1608,11 @@ static void characteristic_free(void *data)
 	queue_destroy(chrc->descs, NULL);
 	queue_destroy(chrc->notify_clients, NULL);
 
-	io_destroy(chrc->write_io);
+	if (chrc->write_io)
+		pipe_io_destroy(chrc->write_io);
 
-	if (chrc->acquire_write)
-		dbus_message_unref(chrc->acquire_write);
+	if (chrc->notify_io)
+		pipe_io_destroy(chrc->notify_io);
 
 	g_free(chrc->path);
 	free(chrc);
-- 
2.9.4


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

* [PATCH v2 08/10] gatt: Add implementation of NotifyAcquired
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (6 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 07/10] gatt: Add implementation of AcquireNotify Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 09/10] client: Add acquire-notify command Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This property indicate if any client has acquire notify thus locking the
access to StartNotify.
---
 src/gatt-client.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/src/gatt-client.c b/src/gatt-client.c
index 571d310..8f3e60c 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -846,6 +846,27 @@ characteristic_write_acquired_exists(const GDBusPropertyTable *property,
 	return (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP);
 }
 
+static gboolean
+characteristic_get_notify_acquired(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct characteristic *chrc = data;
+	dbus_bool_t locked = chrc->notify_io ? TRUE : FALSE;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &locked);
+
+	return TRUE;
+}
+
+static gboolean
+characteristic_notify_acquired_exists(const GDBusPropertyTable *property,
+								void *data)
+{
+	struct characteristic *chrc = data;
+
+	return (chrc->props & BT_GATT_CHRC_PROP_NOTIFY);
+}
+
 static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
 								void *user_data)
 {
@@ -1072,6 +1093,10 @@ static void characteristic_destroy_pipe(struct characteristic *chrc,
 	} else if (chrc->notify_io) {
 		pipe_io_destroy(chrc->notify_io);
 		chrc->notify_io = NULL;
+		g_dbus_emit_property_changed(btd_get_dbus_connection(),
+						chrc->path,
+						GATT_CHARACTERISTIC_IFACE,
+						"NotifyAcquired");
 	}
 }
 
@@ -1133,8 +1158,13 @@ static DBusMessage *characteristic_create_pipe(struct characteristic *chrc,
 						chrc->path,
 						GATT_CHARACTERISTIC_IFACE,
 						"WriteAcquired");
-	} else
+	} else {
 		chrc->notify_io->io = io;
+		g_dbus_emit_property_changed(btd_get_dbus_connection(),
+						chrc->path,
+						GATT_CHARACTERISTIC_IFACE,
+						"NotifyAcquired");
+	}
 
 	DBG("%s: sender %s io %p", dbus_message_get_member(msg),
 					dbus_message_get_sender(msg), io);
@@ -1574,6 +1604,9 @@ static const GDBusPropertyTable characteristic_properties[] = {
 	{ "WriteAcquired", "b", characteristic_get_write_acquired, NULL,
 				characteristic_write_acquired_exists,
 				G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+	{ "NotifyAcquired", "b", characteristic_get_notify_acquired, NULL,
+				characteristic_notify_acquired_exists,
+				G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
 	{ }
 };
 
-- 
2.9.4


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

* [PATCH v2 09/10] client: Add acquire-notify command
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (7 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 08/10] gatt: Add implementation of NotifyAcquired Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-04 15:09 ` [PATCH v2 10/10] client: Add release-notify command Luiz Augusto von Dentz
  2017-07-05 11:34 ` [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds acquire-notify command which uses D-Bus AcquireNotify method
to acquire a file descriptor to read notifications locking the attribute:

[Test peripheral:/service001f/char0020]# acquire-notify
[CHG] Attribute /org/bluez/hci1/dev_56_A0_AA_D0_12_FF/service001f/char0020 NotifyAcquired: yes
AcquireNotify success: fd 7 MTU 65

< ACL Data TX: Handle 3585 flags 0x00 dlen 9
      ATT: Write Request (0x12) len 4
        Handle: 0x0022
          Data: 0200

[CHG] /org/bluez/hci1/dev_56_A0_AA_D0_12_FF/service001f/char0020 Notification:
  00

> ACL Data RX: Handle 3585 flags 0x02 dlen 8
      ATT: Handle Value Indication (0x1d) len 3
        Handle: 0x0021
          Data: 00
---
 Makefile.tools |   4 +-
 client/gatt.c  | 163 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 client/gatt.h  |   2 +
 client/main.c  |  12 +++++
 4 files changed, 154 insertions(+), 27 deletions(-)

diff --git a/Makefile.tools b/Makefile.tools
index c0482fb..0fd6dec 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -9,8 +9,8 @@ client_bluetoothctl_SOURCES = client/main.c \
 					client/advertising.c \
 					client/gatt.h client/gatt.c \
 					monitor/uuid.h monitor/uuid.c
-client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ \
-				-lreadline
+client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \
+				@GLIB_LIBS@ @DBUS_LIBS@ -lreadline
 endif
 
 if MONITOR
diff --git a/client/gatt.c b/client/gatt.c
index 2756efd..0533854 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -38,6 +38,7 @@
 #include <glib.h>
 
 #include "src/shared/queue.h"
+#include "src/shared/io.h"
 #include "gdbus/gdbus.h"
 #include "monitor/uuid.h"
 #include "display.h"
@@ -90,9 +91,13 @@ static GList *managers;
 static GList *uuids;
 
 static GDBusProxy *write_proxy;
-static int write_fd = -1;
+static struct io *write_io;
 static uint16_t write_mtu;
 
+static GDBusProxy *notify_proxy;
+static struct io *notify_io;
+static uint16_t notify_mtu;
+
 static void print_service(struct service *service, const char *description)
 {
 	const char *text;
@@ -229,6 +234,22 @@ void gatt_add_characteristic(GDBusProxy *proxy)
 	print_characteristic(proxy, COLORED_NEW);
 }
 
+static void notify_io_destroy(void)
+{
+	io_destroy(notify_io);
+	notify_io = NULL;
+	notify_proxy = NULL;
+	notify_mtu = 0;
+}
+
+static void write_io_destroy(void)
+{
+	io_destroy(write_io);
+	write_io = NULL;
+	write_proxy = NULL;
+	write_mtu = 0;
+}
+
 void gatt_remove_characteristic(GDBusProxy *proxy)
 {
 	GList *l;
@@ -241,14 +262,10 @@ void gatt_remove_characteristic(GDBusProxy *proxy)
 
 	print_characteristic(proxy, COLORED_DEL);
 
-	if (write_proxy == proxy) {
-		write_proxy = NULL;
-		write_mtu = 0;
-		if (write_fd > 0) {
-			close(write_fd);
-			write_fd = -1;
-		}
-	}
+	if (write_proxy == proxy)
+		write_io_destroy();
+	else if (notify_proxy == proxy)
+		notify_io_destroy();
 }
 
 static void print_desc(struct desc *desc, const char *description)
@@ -633,9 +650,9 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
 	iov.iov_len = i;
 
 	/* Write using the fd if it has been acquired and fit the MTU */
-	if (proxy == write_proxy && (write_fd > 0 && write_mtu >= i)) {
-		rl_printf("Attempting to write fd %d\n", write_fd);
-		if (writev(write_fd, &iov, 1) < 0) {
+	if (proxy == write_proxy && (write_io && write_mtu >= i)) {
+		rl_printf("Attempting to write fd %d\n", io_get_fd(write_io));
+		if (io_send(write_io, &iov, 1) < 0) {
 			rl_printf("Failed to write: %s", strerror(errno));
 			return;
 		}
@@ -666,9 +683,57 @@ void gatt_write_attribute(GDBusProxy *proxy, const char *arg)
 						g_dbus_proxy_get_path(proxy));
 }
 
+static bool pipe_read(struct io *io, void *user_data)
+{
+	uint8_t buf[512];
+	int fd = io_get_fd(io);
+	ssize_t bytes_read;
+
+	if (io != notify_io)
+		return true;
+
+	bytes_read = read(fd, buf, sizeof(buf));
+	if (bytes_read < 0)
+		return false;
+
+	rl_printf("[" COLORED_CHG "] %s Notification:\n",
+			g_dbus_proxy_get_path(notify_proxy));
+	rl_hexdump(buf, bytes_read);
+
+	return true;
+}
+
+static bool pipe_hup(struct io *io, void *user_data)
+{
+	rl_printf("%s closed\n", io == notify_io ? "Notify" : "Write");
+
+	if (io == notify_io)
+		notify_io_destroy();
+	else
+		write_io_destroy();
+
+	return false;
+}
+
+static struct io *pipe_io_new(int fd)
+{
+	struct io *io;
+
+	io = io_new(fd);
+
+	io_set_close_on_destroy(io, true);
+
+	io_set_read_handler(io, pipe_read, NULL, NULL);
+
+	io_set_disconnect_handler(io, pipe_hup, NULL, NULL);
+
+	return io;
+}
+
 static void acquire_write_reply(DBusMessage *message, void *user_data)
 {
 	DBusError error;
+	int fd;
 
 	dbus_error_init(&error);
 
@@ -679,21 +744,19 @@ static void acquire_write_reply(DBusMessage *message, void *user_data)
 		return;
 	}
 
-	if (write_fd > 0) {
-		close(write_fd);
-		write_fd = -1;
-	}
+	if (write_io)
+		write_io_destroy();
 
-	write_mtu = 0;
-
-	if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &write_fd,
+	if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
 					DBUS_TYPE_UINT16, &write_mtu,
 					DBUS_TYPE_INVALID) == false)) {
 		rl_printf("Invalid AcquireWrite response\n");
 		return;
 	}
 
-	rl_printf("AcquireWrite success: fd %d MTU %u\n", write_fd, write_mtu);
+	rl_printf("AcquireWrite success: fd %d MTU %u\n", fd, write_mtu);
+
+	write_io = pipe_io_new(fd);
 }
 
 void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
@@ -718,15 +781,65 @@ void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
 
 void gatt_release_write(GDBusProxy *proxy, const char *arg)
 {
-	if (proxy != write_proxy || write_fd < 0) {
+	if (proxy != write_proxy || !write_io) {
 		rl_printf("Write not acquired\n");
 		return;
 	}
 
-	write_proxy = NULL;
-	close(write_fd);
-	write_fd = -1;
-	write_mtu = 0;
+	write_io_destroy();
+}
+
+static void acquire_notify_reply(DBusMessage *message, void *user_data)
+{
+	DBusError error;
+	int fd;
+
+	dbus_error_init(&error);
+
+	if (dbus_set_error_from_message(&error, message) == TRUE) {
+		rl_printf("Failed to acquire notify: %s\n", error.name);
+		dbus_error_free(&error);
+		write_proxy = NULL;
+		return;
+	}
+
+	if (notify_io) {
+		io_destroy(notify_io);
+		notify_io = NULL;
+	}
+
+	notify_mtu = 0;
+
+	if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
+					DBUS_TYPE_UINT16, &notify_mtu,
+					DBUS_TYPE_INVALID) == false)) {
+		rl_printf("Invalid AcquireWrite response\n");
+		return;
+	}
+
+	rl_printf("AcquireNotify success: fd %d MTU %u\n", fd, notify_mtu);
+
+	notify_io = pipe_io_new(fd);
+}
+
+void gatt_acquire_notify(GDBusProxy *proxy, const char *arg)
+{
+	const char *iface;
+
+	iface = g_dbus_proxy_get_interface(proxy);
+	if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
+		rl_printf("Unable to acquire notify: %s not a characteristic\n",
+						g_dbus_proxy_get_path(proxy));
+		return;
+	}
+
+	if (g_dbus_proxy_method_call(proxy, "AcquireNotify", NULL,
+				acquire_notify_reply, NULL, NULL) == FALSE) {
+		rl_printf("Failed to AcquireNotify\n");
+		return;
+	}
+
+	notify_proxy = proxy;
 }
 
 static void notify_reply(DBusMessage *message, void *user_data)
diff --git a/client/gatt.h b/client/gatt.h
index 6827057..5dba26b 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -41,6 +41,8 @@ void gatt_notify_attribute(GDBusProxy *proxy, bool enable);
 void gatt_acquire_write(GDBusProxy *proxy, const char *arg);
 void gatt_release_write(GDBusProxy *proxy, const char *arg);
 
+void gatt_acquire_notify(GDBusProxy *proxy, const char *arg);
+
 void gatt_add_manager(GDBusProxy *proxy);
 void gatt_remove_manager(GDBusProxy *proxy);
 
diff --git a/client/main.c b/client/main.c
index 7688a23..e0a265d 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1819,6 +1819,16 @@ static void cmd_release_write(const char *arg)
 	gatt_release_write(default_attr, arg);
 }
 
+static void cmd_acquire_notify(const char *arg)
+{
+	if (!default_attr) {
+		rl_printf("No attribute selected\n");
+		return;
+	}
+
+	gatt_acquire_notify(default_attr, arg);
+}
+
 static void cmd_notify(const char *arg)
 {
 	dbus_bool_t enable;
@@ -2298,6 +2308,8 @@ static const struct {
 					"Acquire Write file descriptor" },
 	{ "release-write", NULL, cmd_release_write,
 					"Release Write file descriptor" },
+	{ "acquire-notify", NULL, cmd_acquire_notify,
+					"Acquire Notify file descriptor" },
 	{ "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
 	{ "register-application", "[UUID ...]", cmd_register_app,
 						"Register profile to connect" },
-- 
2.9.4


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

* [PATCH v2 10/10] client: Add release-notify command
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (8 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 09/10] client: Add acquire-notify command Luiz Augusto von Dentz
@ 2017-07-04 15:09 ` Luiz Augusto von Dentz
  2017-07-05 11:34 ` [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-04 15:09 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds release-notify command which closes an existing fd unlocking
the attribute:

[Test peripheral:/service001f/char0020]# release-notify
[CHG] Attribute /org/bluez/hci1/dev_69_16_5B_9A_06_CD/service001f/char0020 NotifyAcquired: no
---
 client/gatt.c | 10 ++++++++++
 client/gatt.h |  1 +
 client/main.c | 12 ++++++++++++
 3 files changed, 23 insertions(+)

diff --git a/client/gatt.c b/client/gatt.c
index 0533854..33e8936 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -842,6 +842,16 @@ void gatt_acquire_notify(GDBusProxy *proxy, const char *arg)
 	notify_proxy = proxy;
 }
 
+void gatt_release_notify(GDBusProxy *proxy, const char *arg)
+{
+	if (proxy != notify_proxy || !notify_io) {
+		rl_printf("Write not acquired\n");
+		return;
+	}
+
+	notify_io_destroy();
+}
+
 static void notify_reply(DBusMessage *message, void *user_data)
 {
 	bool enable = GPOINTER_TO_UINT(user_data);
diff --git a/client/gatt.h b/client/gatt.h
index 5dba26b..9bab429 100644
--- a/client/gatt.h
+++ b/client/gatt.h
@@ -42,6 +42,7 @@ void gatt_acquire_write(GDBusProxy *proxy, const char *arg);
 void gatt_release_write(GDBusProxy *proxy, const char *arg);
 
 void gatt_acquire_notify(GDBusProxy *proxy, const char *arg);
+void gatt_release_notify(GDBusProxy *proxy, const char *arg);
 
 void gatt_add_manager(GDBusProxy *proxy);
 void gatt_remove_manager(GDBusProxy *proxy);
diff --git a/client/main.c b/client/main.c
index e0a265d..8f75f0e 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1829,6 +1829,16 @@ static void cmd_acquire_notify(const char *arg)
 	gatt_acquire_notify(default_attr, arg);
 }
 
+static void cmd_release_notify(const char *arg)
+{
+	if (!default_attr) {
+		rl_printf("No attribute selected\n");
+		return;
+	}
+
+	gatt_release_notify(default_attr, arg);
+}
+
 static void cmd_notify(const char *arg)
 {
 	dbus_bool_t enable;
@@ -2310,6 +2320,8 @@ static const struct {
 					"Release Write file descriptor" },
 	{ "acquire-notify", NULL, cmd_acquire_notify,
 					"Acquire Notify file descriptor" },
+	{ "release-notify", NULL, cmd_release_notify,
+					"Release Notify file descriptor" },
 	{ "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
 	{ "register-application", "[UUID ...]", cmd_register_app,
 						"Register profile to connect" },
-- 
2.9.4


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

* Re: [PATCH v2 01/10] doc/gatt-api: Add AcquireWrite and AcquireNotify
  2017-07-04 15:09 ` [PATCH v2 01/10] doc/gatt-api: " Luiz Augusto von Dentz
@ 2017-07-04 16:01   ` Marcel Holtmann
  0 siblings, 0 replies; 13+ messages in thread
From: Marcel Holtmann @ 2017-07-04 16:01 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz,

> This enables write and notify exclusive access via file descriptors in
> case the characteristic is actually trying to emulate a byte stream
> transfer or have a protocol on top of GATT.
> ---
> doc/gatt-api.txt | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 62 insertions(+)
> 
> diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
> index 6c98b87..3f4a3ca 100644
> --- a/doc/gatt-api.txt
> +++ b/doc/gatt-api.txt
> @@ -91,6 +91,56 @@ Methods		array{byte} ReadValue(dict options)
> 					 org.bluez.Error.NotAuthorized
> 					 org.bluez.Error.NotSupported
> 
> +		fd, uint16 AcquireWrite() [experimental] (Client only)
> +
> +			Acquire write file descriptor and MTU and lock
> +			write access to the characteristic.

Aquire file descriptor and MTU for writing. Usage of WriteValue will be locked ..

Also you need to add an appropriate error code to WriteValue.

> +
> +			Only works with characteristic that has
> +			WriteAcquired property which relies on
> +			write-without-response Flag.
> +
> +			To release the lock the client shall close the file
> +			descriptor, a HUP is generated in case the device
> +			is disconnected.
> +
> +			Note: the MTU can only be negotiated once and is
> +			symmetric therefore this method may be delayed in
> +			order to have the exchange MTU completed, because of
> +			that the file descriptor is closed during
> +			reconnections as the MTU has to be renegotiated.
> +
> +			Possible Errors: org.bluez.Error.Failed
> +					 org.bluez.Error.NotSupported
> +
> +		fd, uint16 AcquireNotify() [experimental] (Client only)
> +
> +			Acquire notify file descriptor and MTU and lock
> +			notifications to the characteristic.

Same as above.

> +
> +			Only works with characteristic that has NotifyAcquired
> +			which relies on notify Flag and no other client have
> +			called StartNotify.
> +
> +			Notification are enabled during this procedure so
> +			StartNotify shall not be called, any notification
> +			will be dispatched via file descriptor therefore the
> +			Value property is no affected during the time where
> +			notify has been acquired.
> +
> +			To release the lock the client shall close the file
> +			descriptor, a HUP is generated in case the device
> +			is disconnected.
> +
> +			Note: the MTU can only be negotiated once and is
> +			symmetric therefore this method may be delayed in
> +			order to have the exchange MTU completed, because of
> +			that the file descriptor is closed during
> +			reconnections as the MTU has to be renegotiated.
> +
> +			Possible Errors: org.bluez.Error.Failed
> +					 org.bluez.Error.NotSupported
> +
> 		void StartNotify()
> 
> 			Starts a notification session from this characteristic
> @@ -125,6 +175,18 @@ Properties	string UUID [read-only]
> 			when a notification or indication is received, upon
> 			which a PropertiesChanged signal will be emitted.
> 
> +		boolean WriteAcquired [read-only, optional]
> +
> +			True, if this characteristic has been acquire by any

has been acquired ..

> +			client using AcquireWrite. This properties is ommited
> +			in case write-without-response flag is not set.
> +
> +		boolean NotifyAcquired [read-only, optional]
> +
> +			True, if this characteristic has been acquire by any

See above.

> +			client using AcquireNotify. This properties is ommited
> +			in case notify flag is not set.
> +
> 		boolean Notifying [read-only, optional]
> 
> 			True, if notifications or indications on this

Otherwise, looks good. Lets get this patch set merged.

Regards

Marcel


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

* Re: [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify
  2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
                   ` (9 preceding siblings ...)
  2017-07-04 15:09 ` [PATCH v2 10/10] client: Add release-notify command Luiz Augusto von Dentz
@ 2017-07-05 11:34 ` Luiz Augusto von Dentz
  10 siblings, 0 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2017-07-05 11:34 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

On Tue, Jul 4, 2017 at 6:09 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This set adds 2 new methods to GattCharacteristics1, thse deal with
> attributes that attempts to emulate a byte stream transfer, or a protocol
> on top of GATT, using write without response and notifications.
>
> v2:
> - Rename WriteLocked and NotifyLocked to WriteAcquired and NotifyAcquired
> - Make WriteAcquired and NotifyAcquired optional so they only appear if
> the required flags are supported.
> - Make sure O_CLOEXEC and O_NONBLOCK are set in the flags passed to pipe2.
>
> Luiz Augusto von Dentz (10):
>   doc/gatt-api: Add AcquireWrite and AcquireNotify
>   shared/gatt-client: Allow multiple ready callbacks
>   gatt: Add implementation of AcquireWrite
>   gatt: Add implementation of WriteAcquired
>   client: Add acquire-write command
>   client: Add release-write command
>   gatt: Add implementation of AcquireNotify
>   gatt: Add implementation of NotifyAcquired
>   client: Add acquire-notify command
>   client: Add release-notify command
>
>  Makefile.tools           |   4 +-
>  client/gatt.c            | 209 +++++++++++++++++++++++++++
>  client/gatt.h            |   6 +
>  client/main.c            |  48 +++++++
>  doc/gatt-api.txt         |  62 ++++++++
>  peripheral/gatt.c        |   4 +-
>  src/device.c             |  16 ++-
>  src/gatt-client.c        | 367 +++++++++++++++++++++++++++++++++++++++++++++++
>  src/shared/gatt-client.c |  60 ++++++--
>  src/shared/gatt-client.h |   4 +-
>  tools/btgatt-client.c    |   2 +-
>  unit/test-gatt.c         |   4 +-
>  12 files changed, 759 insertions(+), 27 deletions(-)
>
> --
> 2.9.4

Applied after adjusting documentation according to the review comments.


-- 
Luiz Augusto von Dentz

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

end of thread, other threads:[~2017-07-05 11:34 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-04 15:09 [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 01/10] doc/gatt-api: " Luiz Augusto von Dentz
2017-07-04 16:01   ` Marcel Holtmann
2017-07-04 15:09 ` [PATCH v2 02/10] shared/gatt-client: Allow multiple ready callbacks Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 03/10] gatt: Add implementation of AcquireWrite Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 04/10] gatt: Add implementation of WriteAcquired Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 05/10] client: Add acquire-write command Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 06/10] client: Add release-write command Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 07/10] gatt: Add implementation of AcquireNotify Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 08/10] gatt: Add implementation of NotifyAcquired Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 09/10] client: Add acquire-notify command Luiz Augusto von Dentz
2017-07-04 15:09 ` [PATCH v2 10/10] client: Add release-notify command Luiz Augusto von Dentz
2017-07-05 11:34 ` [PATCH v2 00/10] gatt: Add AcquireWrite and AcquireNotify Luiz Augusto von Dentz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.