diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 04fb4cb..a78e209 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
#include <assert.h>
#include <limits.h>
+#include <sys/uio.h>
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
struct bt_gatt_client *client;
int ref_count;
uint16_t value_handle;
- uint16_t orig_offset;
uint16_t offset;
- struct queue *blobs;
+ struct iovec iov;
bt_gatt_client_read_callback_t callback;
void *user_data;
bt_gatt_client_destroy_func_t destroy;
};
-struct blob {
- uint8_t *data;
- uint16_t offset;
- uint16_t length;
-};
-
-static struct blob *create_blob(const uint8_t *data, uint16_t len,
- uint16_t offset)
-{
- struct blob *blob;
-
- blob = new0(struct blob, 1);
- if (!blob)
- return NULL;
-
- /* Truncate if the data would exceed maximum length */
- if (offset + len > BT_ATT_MAX_VALUE_LEN)
- len = BT_ATT_MAX_VALUE_LEN - offset;
-
- blob->data = malloc(len);
- if (!blob->data) {
- free(blob);
- return NULL;
- }
-
- memcpy(blob->data, data, len);
- blob->length = len;
- blob->offset = offset;
-
- return blob;
-}
-
-static void destroy_blob(void *data)
-{
- struct blob *blob = data;
-
- free(blob->data);
- free(blob);
-}
-
static void destroy_read_long_op(void *data)
{
struct read_long_op *op = data;
if (op->destroy)
op->destroy(op->user_data);
- queue_destroy(op->blobs, destroy_blob);
-
+ free(op->iov.iov_base);
free(op);
}
-static void append_blob(void *data, void *user_data)
+static bool append_chunk(struct read_long_op *op, const uint8_t *data,
+ uint16_t len)
{
- struct blob *blob = data;
- uint8_t *value = user_data;
-
- memcpy(value + blob->offset, blob->data, blob->length);
-}
+ void *buf;
-static void complete_read_long_op(struct read_long_op *op, bool success,
- uint8_t att_ecode)
-{
- uint8_t *value = NULL;
- uint16_t length = 0;
-
- if (!success)
- goto done;
-
- length = op->offset - op->orig_offset;
+ /* Truncate if the data would exceed maximum length */
+ if (op->offset + len > BT_ATT_MAX_VALUE_LEN)
+ len = BT_ATT_MAX_VALUE_LEN - op->offset;
- if (!length)
- goto done;
+ buf = realloc(op->iov.iov_base, op->iov.iov_len + len);
+ if (!buf)
+ return false;
- value = malloc(length);
- if (!value) {
- success = false;
- goto done;
- }
+ op->iov.iov_base = buf;
- queue_foreach(op->blobs, append_blob, value - op->orig_offset);
+ memcpy(op->iov.iov_base + op->iov.iov_len, data, len);
-done:
- if (op->callback)
- op->callback(success, att_ecode, value, length, op->user_data);
+ op->iov.iov_len += len;
+ op->offset += len;
- free(value);
+ return true;
}
static void read_long_cb(uint8_t opcode, const void *pdu,
{
struct request *req = user_data;
struct read_long_op *op = req->data;
- struct blob *blob;
bool success;
uint8_t att_ecode = 0;
if (!length)
goto success;
- blob = create_blob(pdu, length, op->offset);
- if (!blob) {
+ if (!append_chunk(op, pdu, length)) {
success = false;
goto done;
}
- queue_push_tail(op->blobs, blob);
- op->offset += blob->length;
if (op->offset >= BT_ATT_MAX_VALUE_LEN)
goto success;
success = true;
done:
- complete_read_long_op(op, success, att_ecode);
+ if (op->callback)
+ op->callback(success, att_ecode, op->iov.iov_base,
+ op->iov.iov_len, op->user_data);
}
unsigned int bt_gatt_client_read_long_value(struct bt_gatt_client *client,
if (!op)
return 0;
- op->blobs = queue_new();
- if (!op->blobs) {
- free(op);
- return 0;
- }
-
req = request_create(client);
if (!req) {
- queue_destroy(op->blobs, free);
free(op);
return 0;
}
op->client = client;
op->value_handle = value_handle;
- op->orig_offset = offset;
op->offset = offset;
op->callback = callback;
op->user_data = user_data;