From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH v2 07/10] client: Implement AcquireWrite for server
Date: Wed, 20 Sep 2017 10:44:14 +0300 [thread overview]
Message-ID: <20170920074417.30435-8-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20170920074417.30435-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This enables IO via file descriptors using AcquireWrite if server
implements it.
---
client/gatt.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 158 insertions(+), 8 deletions(-)
diff --git a/client/gatt.c b/client/gatt.c
index ab74aa695..6401fbd1a 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -32,6 +32,7 @@
#include <stdbool.h>
#include <sys/uio.h>
#include <wordexp.h>
+#include <fcntl.h>
#include <readline/readline.h>
#include <readline/history.h>
@@ -73,6 +74,8 @@ struct chrc {
GList *descs;
int value_len;
uint8_t *value;
+ uint16_t mtu;
+ struct io *write_io;
};
struct service {
@@ -683,19 +686,25 @@ void gatt_write_attribute(GDBusProxy *proxy, const char *arg)
static bool pipe_read(struct io *io, void *user_data)
{
+ struct chrc *chrc = user_data;
uint8_t buf[512];
int fd = io_get_fd(io);
ssize_t bytes_read;
- if (io != notify_io.io)
+ if (io != notify_io.io && !chrc)
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_io.proxy));
+ if (chrc)
+ rl_printf("[" COLORED_CHG "] Attribute %s written:\n",
+ chrc->path);
+ else
+ rl_printf("[" COLORED_CHG "] %s Notification:\n",
+ g_dbus_proxy_get_path(notify_io.proxy));
+
rl_hexdump(buf, bytes_read);
return true;
@@ -703,6 +712,17 @@ static bool pipe_read(struct io *io, void *user_data)
static bool pipe_hup(struct io *io, void *user_data)
{
+ struct chrc *chrc = user_data;
+
+ if (chrc) {
+ rl_printf("Attribute %s Write pipe closed\n", chrc->path);
+ if (chrc->write_io) {
+ io_destroy(chrc->write_io);
+ chrc->write_io = NULL;
+ }
+ return false;
+ }
+
rl_printf("%s closed\n", io == notify_io.io ? "Notify" : "Write");
if (io == notify_io.io)
@@ -713,7 +733,7 @@ static bool pipe_hup(struct io *io, void *user_data)
return false;
}
-static struct io *pipe_io_new(int fd)
+static struct io *pipe_io_new(int fd, void *user_data)
{
struct io *io;
@@ -721,9 +741,9 @@ static struct io *pipe_io_new(int fd)
io_set_close_on_destroy(io, true);
- io_set_read_handler(io, pipe_read, NULL, NULL);
+ io_set_read_handler(io, pipe_read, user_data, NULL);
- io_set_disconnect_handler(io, pipe_hup, NULL, NULL);
+ io_set_disconnect_handler(io, pipe_hup, user_data, NULL);
return io;
}
@@ -754,7 +774,7 @@ static void acquire_write_reply(DBusMessage *message, void *user_data)
rl_printf("AcquireWrite success: fd %d MTU %u\n", fd, write_io.mtu);
- write_io.io = pipe_io_new(fd);
+ write_io.io = pipe_io_new(fd, NULL);
}
void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
@@ -817,7 +837,7 @@ static void acquire_notify_reply(DBusMessage *message, void *user_data)
rl_printf("AcquireNotify success: fd %d MTU %u\n", fd, notify_io.mtu);
- notify_io.io = pipe_io_new(fd);
+ notify_io.io = pipe_io_new(fd, NULL);
}
void gatt_acquire_notify(GDBusProxy *proxy, const char *arg)
@@ -1302,12 +1322,41 @@ static gboolean chrc_get_flags(const GDBusPropertyTable *property,
return TRUE;
}
+static gboolean chrc_get_write_acquired(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct chrc *chrc = data;
+ dbus_bool_t value;
+
+ value = chrc->write_io ? TRUE : FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+ return TRUE;
+}
+
+static gboolean chrc_write_acquired_exists(const GDBusPropertyTable *property,
+ void *data)
+{
+ struct chrc *chrc = data;
+ int i;
+
+ for (i = 0; chrc->flags[i]; i++) {
+ if (!strcmp("write-without-response", chrc->flags[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static const GDBusPropertyTable chrc_properties[] = {
{ "UUID", "s", chrc_get_uuid, NULL, NULL },
{ "Service", "o", chrc_get_service, NULL, NULL },
{ "Value", "ay", chrc_get_value, NULL, NULL },
{ "Notifying", "b", chrc_get_notifying, NULL, NULL },
{ "Flags", "as", chrc_get_flags, NULL, NULL },
+ { "WriteAcquired", "b", chrc_get_write_acquired, NULL,
+ chrc_write_acquired_exists },
{ }
};
@@ -1369,6 +1418,105 @@ static DBusMessage *chrc_write_value(DBusConnection *conn, DBusMessage *msg,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
+static int parse_options(DBusMessageIter *iter, struct chrc *chrc)
+{
+ DBusMessageIter dict;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(iter, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ const char *key;
+ DBusMessageIter value, entry;
+ int var;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ var = dbus_message_iter_get_arg_type(&value);
+ if (strcasecmp(key, "Device") == 0) {
+ if (var != DBUS_TYPE_OBJECT_PATH)
+ return -EINVAL;
+ } else if (strcasecmp(key, "MTU") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ return -EINVAL;
+ dbus_message_iter_get_basic(&value, &chrc->mtu);
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ return 0;
+}
+
+static DBusMessage *chrc_create_pipe(struct chrc *chrc, DBusMessage *msg)
+{
+ int pipefd[2];
+ struct io *io;
+ bool dir;
+ DBusMessage *reply;
+
+ if (pipe2(pipefd, O_DIRECT | O_NONBLOCK | O_CLOEXEC) < 0)
+ return g_dbus_create_error(msg, "org.bluez.Error.Failed", "%s",
+ strerror(errno));
+
+ dir = dbus_message_has_member(msg, "AcquireWrite");
+
+ io = pipe_io_new(pipefd[!dir], chrc);
+ if (!io) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return g_dbus_create_error(msg, "org.bluez.Error.Failed", "%s",
+ strerror(errno));
+ }
+
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_UNIX_FD, &pipefd[dir],
+ DBUS_TYPE_UINT16, &chrc->mtu,
+ DBUS_TYPE_INVALID);
+
+ close(pipefd[dir]);
+
+ chrc->write_io = io;
+
+ rl_printf("[" COLORED_CHG "] Attribute %s Write pipe acquired\n",
+ chrc->path);
+
+ return reply;
+}
+
+static DBusMessage *chrc_acquire_write(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct chrc *chrc = user_data;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (chrc->write_io)
+ return g_dbus_create_error(msg,
+ "org.bluez.Error.NotPermitted",
+ NULL);
+
+ if (parse_options(&iter, chrc))
+ return g_dbus_create_error(msg,
+ "org.bluez.Error.InvalidArguments",
+ NULL);
+
+ reply = chrc_create_pipe(chrc, msg);
+
+ if (chrc->write_io)
+ g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
+ "WriteAcquired");
+
+ return reply;
+}
+
static DBusMessage *chrc_start_notify(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
@@ -1420,6 +1568,8 @@ static const GDBusMethodTable chrc_methods[] = {
{ GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
{ "options", "a{sv}" }),
NULL, chrc_write_value) },
+ { GDBUS_METHOD("AcquireWrite", GDBUS_ARGS({ "options", "a{sv}" }),
+ NULL, chrc_acquire_write) },
{ GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chrc_start_notify) },
{ GDBUS_METHOD("StopNotify", NULL, NULL, chrc_stop_notify) },
{ GDBUS_METHOD("Confirm", NULL, NULL, chrc_confirm) },
--
2.13.5
next prev parent reply other threads:[~2017-09-20 7:44 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-20 7:44 [PATCH v2 00/10] gatt: Add server support for AcquireWrite and AcquireNotify Luiz Augusto von Dentz
2017-09-20 7:44 ` [PATCH v2 01/10] gatt: Remove useless debug Luiz Augusto von Dentz
2017-09-20 7:44 ` [PATCH v2 02/10] client: Rework variables for AcquireWrite/AcquireNotify Luiz Augusto von Dentz
2017-09-20 7:44 ` [PATCH v2 03/10] doc/gatt-api: Add server support for AcquireWrite and AcquireNotify Luiz Augusto von Dentz
2017-09-20 7:44 ` [PATCH v2 04/10] shared/gatt-server: Add bt_gatt_server_get_mtu Luiz Augusto von Dentz
2017-09-20 7:44 ` [PATCH v2 05/10] shared/gatt-db: Add gatt_db_attribute_get_user_data Luiz Augusto von Dentz
2017-09-20 7:44 ` [PATCH v2 06/10] gatt: Implement AcquireWrite for server Luiz Augusto von Dentz
2017-09-29 5:04 ` Yunhan Wang
2017-09-29 6:54 ` Luiz Augusto von Dentz
2017-09-29 7:14 ` Yunhan Wang
2017-09-29 7:22 ` Luiz Augusto von Dentz
2017-09-29 7:50 ` Yunhan Wang
2017-09-29 8:02 ` Luiz Augusto von Dentz
2017-09-30 3:39 ` Yunhan Wang
2017-10-02 11:57 ` Luiz Augusto von Dentz
2017-10-03 0:24 ` Yunhan Wang
2017-09-20 7:44 ` Luiz Augusto von Dentz [this message]
2017-09-20 7:44 ` [PATCH v2 08/10] gatt: Implement AcquireNotify " Luiz Augusto von Dentz
2017-09-29 4:47 ` Yunhan Wang
2017-09-29 7:03 ` Luiz Augusto von Dentz
2017-10-03 6:13 ` Yunhan Wang
2017-10-03 7:36 ` Luiz Augusto von Dentz
2017-10-03 18:48 ` Yunhan Wang
2017-09-20 7:44 ` [PATCH v2 09/10] client: " Luiz Augusto von Dentz
2017-09-20 7:44 ` [PATCH v2 10/10] gatt: Update signature of AcquireWrite and AcquireNotify Luiz Augusto von Dentz
2017-09-21 7:49 ` [PATCH v2 00/10] gatt: Add server support for " Luiz Augusto von Dentz
2017-09-21 18:15 ` Yunhan Wang
2017-09-22 10:58 ` Luiz Augusto von Dentz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170920074417.30435-8-luiz.dentz@gmail.com \
--to=luiz.dentz@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).