From: Arman Uguray <armansito@chromium.org>
To: linux-bluetooth@vger.kernel.org
Cc: Arman Uguray <armansito@chromium.org>
Subject: [PATCH BlueZ v2 03/14] shared/gatt-client: Make long-write cancelable
Date: Wed, 7 Jan 2015 21:48:17 -0800 [thread overview]
Message-ID: <1420696108-29699-4-git-send-email-armansito@chromium.org> (raw)
In-Reply-To: <1420696108-29699-1-git-send-email-armansito@chromium.org>
This patch extends the GATT request ids in bt_gatt_client to
bt_gatt_client_write_long_value.
---
src/shared/gatt-client.c | 162 ++++++++++++++++++++++++++++++-----------------
src/shared/gatt-client.h | 2 +-
2 files changed, 104 insertions(+), 60 deletions(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 362fc32..083bcd2 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -101,6 +101,7 @@ struct bt_gatt_client {
struct request {
struct bt_gatt_client *client;
+ bool long_write;
bool removed;
int ref_count;
unsigned int id;
@@ -1473,8 +1474,6 @@ static void notify_cb(uint8_t opcode, const void *pdu, uint16_t length,
bt_gatt_client_unref(client);
}
-static void long_write_op_unref(void *data);
-
static void bt_gatt_client_free(struct bt_gatt_client *client)
{
bt_gatt_client_cancel_all(client);
@@ -1495,7 +1494,7 @@ static void bt_gatt_client_free(struct bt_gatt_client *client)
gatt_db_unref(client->db);
queue_destroy(client->svc_chngd_queue, free);
- queue_destroy(client->long_write_queue, long_write_op_unref);
+ queue_destroy(client->long_write_queue, request_unref);
queue_destroy(client->notify_list, notify_data_unref);
queue_destroy(client->notify_chrcs, notify_chrc_free);
queue_destroy(client->pending_requests, request_unref);
@@ -1676,9 +1675,16 @@ static bool match_req_id(const void *a, const void *b)
return req->id == id;
}
+static void cancel_long_write_cb(uint8_t opcode, const void *pdu, uint16_t len,
+ void *user_data)
+{
+ /* Do nothing */
+}
+
bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id)
{
struct request *req;
+ uint8_t pdu = 0x00;
if (!client || !id || !client->att)
return false;
@@ -1690,15 +1696,48 @@ bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id)
req->removed = true;
- return bt_att_cancel(client->att, req->att_id);
+ if (!bt_att_cancel(client->att, req->att_id) && !req->long_write)
+ return false;
+
+ /* If this was a long-write, we need to abort all prepared writes */
+ if (!req->long_write)
+ return true;
+
+ if (!req->att_id)
+ queue_remove(client->long_write_queue, req);
+ else
+ bt_att_send(client->att, BT_ATT_OP_EXEC_WRITE_REQ,
+ &pdu, sizeof(pdu),
+ cancel_long_write_cb,
+ NULL, NULL);
+
+ if (queue_isempty(client->long_write_queue))
+ client->in_long_write = false;
+
+ return true;
}
static void cancel_request(void *data)
{
struct request *req = data;
+ uint8_t pdu = 0x00;
req->removed = true;
bt_att_cancel(req->client->att, req->att_id);
+
+ if (!req->long_write)
+ return;
+
+ if (!req->att_id)
+ queue_remove(req->client->long_write_queue, req);
+
+ if (queue_isempty(req->client->long_write_queue))
+ req->client->in_long_write = false;
+
+ bt_att_send(req->client->att, BT_ATT_OP_EXEC_WRITE_REQ,
+ &pdu, sizeof(pdu),
+ cancel_long_write_cb,
+ NULL, NULL);
}
bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
@@ -2218,7 +2257,6 @@ unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client,
struct long_write_op {
struct bt_gatt_client *client;
- int ref_count;
bool reliable;
bool success;
uint8_t att_ecode;
@@ -2234,20 +2272,10 @@ struct long_write_op {
bt_gatt_client_destroy_func_t destroy;
};
-static struct long_write_op *long_write_op_ref(struct long_write_op *op)
-{
- __sync_fetch_and_add(&op->ref_count, 1);
-
- return op;
-}
-
-static void long_write_op_unref(void *data)
+static void long_write_op_free(void *data)
{
struct long_write_op *op = data;
- if (__sync_sub_and_fetch(&op->ref_count, 1))
- return;
-
if (op->destroy)
op->destroy(op->user_data);
@@ -2257,11 +2285,12 @@ static void long_write_op_unref(void *data)
static void prepare_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
void *user_data);
-static void complete_write_long_op(struct long_write_op *op, bool success,
+static void complete_write_long_op(struct request *req, bool success,
uint8_t att_ecode, bool reliable_error);
-static void handle_next_prep_write(struct long_write_op *op)
+static void handle_next_prep_write(struct request *req)
{
+ struct long_write_op *op = req->data;
bool success = true;
uint8_t *pdu;
@@ -2275,12 +2304,13 @@ static void handle_next_prep_write(struct long_write_op *op)
put_le16(op->offset + op->index, pdu + 2);
memcpy(pdu + 4, op->value + op->index, op->cur_length);
- if (!bt_att_send(op->client->att, BT_ATT_OP_PREP_WRITE_REQ,
+ req->att_id = bt_att_send(op->client->att, BT_ATT_OP_PREP_WRITE_REQ,
pdu, op->cur_length + 4,
prepare_write_cb,
- long_write_op_ref(op),
- long_write_op_unref)) {
- long_write_op_unref(op);
+ request_ref(req),
+ request_unref);
+ if (!req->att_id) {
+ request_unref(req);
success = false;
}
@@ -2294,34 +2324,36 @@ static void handle_next_prep_write(struct long_write_op *op)
return;
done:
- complete_write_long_op(op, success, 0, false);
+ complete_write_long_op(req, success, 0, false);
}
static void start_next_long_write(struct bt_gatt_client *client)
{
- struct long_write_op *op;
+ struct request *req;
if (queue_isempty(client->long_write_queue)) {
client->in_long_write = false;
return;
}
- op = queue_pop_head(client->long_write_queue);
- if (!op)
+ req = queue_pop_head(client->long_write_queue);
+ if (!req)
return;
- handle_next_prep_write(op);
+ handle_next_prep_write(req);
- /* send_next_prep_write adds an extra ref. Unref here to clean up if
+ /*
+ * send_next_prep_write adds an extra ref. Unref here to clean up if
* necessary, since we also added a ref before pushing to the queue.
*/
- long_write_op_unref(op);
+ request_unref(req);
}
static void execute_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
void *user_data)
{
- struct long_write_op *op = user_data;
+ struct request *req = user_data;
+ struct long_write_op *op = req->data;
bool success = op->success;
uint8_t att_ecode = op->att_ecode;
@@ -2338,9 +2370,10 @@ static void execute_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
start_next_long_write(op->client);
}
-static void complete_write_long_op(struct long_write_op *op, bool success,
+static void complete_write_long_op(struct request *req, bool success,
uint8_t att_ecode, bool reliable_error)
{
+ struct long_write_op *op = req->data;
uint8_t pdu;
op->success = success;
@@ -2352,14 +2385,16 @@ static void complete_write_long_op(struct long_write_op *op, bool success,
else
pdu = 0x00; /* Cancel */
- if (bt_att_send(op->client->att, BT_ATT_OP_EXEC_WRITE_REQ,
+ req->att_id = bt_att_send(op->client->att, BT_ATT_OP_EXEC_WRITE_REQ,
&pdu, sizeof(pdu),
execute_write_cb,
- long_write_op_ref(op),
- long_write_op_unref))
+ request_ref(req),
+ request_unref);
+ if (req->att_id)
return;
- long_write_op_unref(op);
+
+ request_unref(req);
success = false;
if (op->callback)
@@ -2371,7 +2406,8 @@ static void complete_write_long_op(struct long_write_op *op, bool success,
static void prepare_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
void *user_data)
{
- struct long_write_op *op = user_data;
+ struct request *req = user_data;
+ struct long_write_op *op = req->data;
bool success = true;
bool reliable_error = false;
uint8_t att_ecode = 0;
@@ -2422,15 +2458,15 @@ static void prepare_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
op->index = next_index;
op->cur_length = MIN(op->length - op->index,
bt_att_get_mtu(op->client->att) - 5);
- handle_next_prep_write(op);
+ handle_next_prep_write(req);
return;
}
done:
- complete_write_long_op(op, success, att_ecode, reliable_error);
+ complete_write_long_op(req, success, att_ecode, reliable_error);
}
-bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
bool reliable,
uint16_t value_handle, uint16_t offset,
const uint8_t *value, uint16_t length,
@@ -2438,30 +2474,37 @@ bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
void *user_data,
bt_gatt_client_destroy_func_t destroy)
{
+ struct request *req;
struct long_write_op *op;
uint8_t *pdu;
- bool status;
if (!client)
- return false;
+ return 0;
if ((size_t)(length + offset) > UINT16_MAX)
- return false;
+ return 0;
/* Don't allow writing a 0-length value using this procedure. The
* upper-layer should use bt_gatt_write_value for that instead.
*/
if (!length || !value)
- return false;
+ return 0;
op = new0(struct long_write_op, 1);
if (!op)
- return false;
+ return 0;
op->value = malloc(length);
if (!op->value) {
free(op);
- return false;
+ return 0;
+ }
+
+ req = request_create(client);
+ if (!req) {
+ free(op->value);
+ free(op);
+ return 0;
}
memcpy(op->value, value, length);
@@ -2476,40 +2519,41 @@ bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
op->user_data = user_data;
op->destroy = destroy;
+ req->data = op;
+ req->destroy = long_write_op_free;
+ req->long_write = true;
+
if (client->in_long_write) {
- queue_push_tail(client->long_write_queue,
- long_write_op_ref(op));
- return true;
+ queue_push_tail(client->long_write_queue, req);
+ return req->id;
}
pdu = malloc(op->cur_length + 4);
if (!pdu) {
free(op->value);
free(op);
- return false;
+ return 0;
}
put_le16(value_handle, pdu);
put_le16(offset, pdu + 2);
memcpy(pdu + 4, op->value, op->cur_length);
- status = bt_att_send(client->att, BT_ATT_OP_PREP_WRITE_REQ,
+ req->att_id = bt_att_send(client->att, BT_ATT_OP_PREP_WRITE_REQ,
pdu, op->cur_length + 4,
- prepare_write_cb,
- long_write_op_ref(op),
- long_write_op_unref);
-
+ prepare_write_cb, req,
+ request_unref);
free(pdu);
- if (!status) {
- free(op->value);
- free(op);
- return false;
+ if (!req->att_id) {
+ op->destroy = NULL;
+ request_unref(req);
+ return 0;
}
client->in_long_write = true;
- return true;
+ return req->id;
}
static bool match_notify_chrc_value_handle(const void *a, const void *b)
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 74d781c..9a00feb 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -102,7 +102,7 @@ unsigned int bt_gatt_client_write_value(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_write_long_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
bool reliable,
uint16_t value_handle, uint16_t offset,
const uint8_t *value, uint16_t length,
--
2.2.0.rc0.207.ga3a616c
next prev parent reply other threads:[~2015-01-08 5:48 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-08 5:48 [PATCH BlueZ v2 00/14] Implmenet doc/gatt-api.txt for client Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 01/14] core: gatt: Expose charac. extended properties Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 02/14] shared/gatt-client: Make read/write cancelable Arman Uguray
2015-01-08 5:48 ` Arman Uguray [this message]
2015-01-08 5:48 ` [PATCH BlueZ v2 04/14] core: gatt: Cancel pending reads/writes Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 05/14] shared/gatt-db: Add gatt_db_attribute_reset Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 06/14] core: gatt: Reset value in db when caching Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 07/14] core: gatt: Issue long write for reliable-write Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 08/14] core: gatt: Handle Service Changed Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 09/14] core: device: Fix GATT profile probing Arman Uguray
2015-01-12 22:04 ` Luiz Augusto von Dentz
2015-01-08 5:48 ` [PATCH BlueZ v2 10/14] profiles/gap: Fix probe/accept behavior Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 11/14] core: service: Remove GATT handle logic Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 12/14] shared/gatt-db: Fix crash in gatt_db_find_by_type Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 13/14] shared/gatt-db: Add "claimed" field to services Arman Uguray
2015-01-08 5:48 ` [PATCH BlueZ v2 14/14] core: gatt: Use "claimed" instead of "active" Arman Uguray
2015-01-12 21:37 ` [PATCH BlueZ v2 00/14] Implmenet doc/gatt-api.txt for client Arman Uguray
2015-01-12 22: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=1420696108-29699-4-git-send-email-armansito@chromium.org \
--to=armansito@chromium.org \
--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).