gattlib.h: Hide implementation specific attributes in gatt_connection_t.context

pull/21/head
Olivier Martin 2017-03-15 01:37:33 +01:00
parent ee2fabaf3f
commit 1655e8c329
10 changed files with 122 additions and 42 deletions

View File

@ -80,23 +80,26 @@ static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
olen = enc_confirmation(opdu, sizeof(opdu));
if (olen > 0)
g_attrib_send(conn->attrib, 0,
if (olen > 0) {
gattlib_context_t* conn_context = conn->context;
g_attrib_send(conn_context->attrib, 0,
#if BLUEZ_VERSION_MAJOR == 4
opdu[0],
#endif
opdu, olen, NULL, NULL, NULL);
}
}
static gboolean io_listen_cb(gpointer user_data) {
gatt_connection_t *conn = user_data;
gattlib_context_t* conn_context = conn->context;
g_attrib_register(conn->attrib, ATT_OP_HANDLE_NOTIFY,
g_attrib_register(conn_context->attrib, ATT_OP_HANDLE_NOTIFY,
#if BLUEZ_VERSION_MAJOR == 5
GATTRIB_ALL_HANDLES,
#endif
events_handler, conn, NULL);
g_attrib_register(conn->attrib, ATT_OP_HANDLE_IND,
g_attrib_register(conn_context->attrib, ATT_OP_HANDLE_IND,
#if BLUEZ_VERSION_MAJOR == 5
GATTRIB_ALL_HANDLES,
#endif
@ -116,10 +119,12 @@ static void io_connect_cb(GIOChannel *io, GError *err, gpointer user_data) {
io_connect_arg->connect_cb(NULL);
}
} else {
gattlib_context_t* conn_context = io_connect_arg->conn->context;
#if BLUEZ_VERSION_MAJOR == 4
io_connect_arg->conn->attrib = g_attrib_new(io);
conn_context->attrib = g_attrib_new(io);
#else
io_connect_arg->conn->attrib = g_attrib_new(io, BT_ATT_DEFAULT_LE_MTU, false);
conn_context->attrib = g_attrib_new(io, BT_ATT_DEFAULT_LE_MTU, false);
#endif
//
@ -213,11 +218,18 @@ static gatt_connection_t *initialize_gattlib_connection(const gchar *src, const
return NULL;
}
gattlib_context_t* conn_context = calloc(sizeof(gattlib_context_t), 1);
if (conn_context == NULL) {
return NULL;
}
gatt_connection_t* conn = calloc(sizeof(gatt_connection_t), 1);
if (conn == NULL) {
return NULL;
}
conn->context = conn_context;
/* Intialize bt_io_connect argument */
io_connect_arg->conn = conn;
io_connect_arg->connect_cb = connect_cb;
@ -225,8 +237,8 @@ static gatt_connection_t *initialize_gattlib_connection(const gchar *src, const
io_connect_arg->timeout = FALSE;
io_connect_arg->error = NULL;
if (psm == 0)
conn->io = bt_io_connect(
if (psm == 0) {
conn_context->io = bt_io_connect(
#if BLUEZ_VERSION_MAJOR == 4
BT_IO_L2CAP,
#endif
@ -241,8 +253,8 @@ static gatt_connection_t *initialize_gattlib_connection(const gchar *src, const
BT_IO_OPT_SEC_LEVEL, sec_level,
BT_IO_OPT_TIMEOUT, CONNECTION_TIMEOUT,
BT_IO_OPT_INVALID);
else
conn->io = bt_io_connect(
} else {
conn_context->io = bt_io_connect(
#if BLUEZ_VERSION_MAJOR == 4
BT_IO_L2CAP,
#endif
@ -257,10 +269,13 @@ static gatt_connection_t *initialize_gattlib_connection(const gchar *src, const
BT_IO_OPT_SEC_LEVEL, sec_level,
BT_IO_OPT_TIMEOUT, CONNECTION_TIMEOUT,
BT_IO_OPT_INVALID);
}
if (err) {
fprintf(stderr, "%s\n", err->message);
g_error_free(err);
free(conn_context);
free(conn);
return NULL;
} else {
return conn;
@ -351,15 +366,19 @@ gatt_connection_t *gattlib_connect(const char *src, const char *dst,
}
int gattlib_disconnect(gatt_connection_t* connection) {
gattlib_context_t* conn_context = connection->context;
#if BLUEZ_VERSION_MAJOR == 4
// Stop the I/O Channel
GIOStatus status = g_io_channel_shutdown(connection->io, FALSE, NULL);
GIOStatus status = g_io_channel_shutdown(conn_context->io, FALSE, NULL);
assert(status == G_IO_STATUS_NORMAL);
g_io_channel_unref(connection->io);
g_io_channel_unref(conn_context->io);
#endif
g_attrib_unref(connection->attrib);
g_attrib_unref(conn_context->attrib);
free(conn_context->characteristics);
free(connection->context);
free(connection);
//TODO: Add a mutex around this code to avoid a race condition

View File

@ -77,7 +77,8 @@ int gattlib_discover_primary(gatt_connection_t* connection, gattlib_primary_serv
bzero(&user_data, sizeof(user_data));
user_data.discovered = FALSE;
ret = gatt_discover_primary(connection->attrib, NULL, primary_all_cb, &user_data);
gattlib_context_t* conn_context = connection->context;
ret = gatt_discover_primary(conn_context->attrib, NULL, primary_all_cb, &user_data);
if (ret == 0) {
fprintf(stderr, "Fail to discover primary services.\n");
return 1;
@ -140,7 +141,8 @@ int gattlib_discover_char_range(gatt_connection_t* connection, int start, int en
bzero(&user_data, sizeof(user_data));
user_data.discovered = FALSE;
ret = gatt_discover_char(connection->attrib, start, end, NULL, characteristic_cb, &user_data);
gattlib_context_t* conn_context = connection->context;
ret = gatt_discover_char(conn_context->attrib, start, end, NULL, characteristic_cb, &user_data);
if (ret == 0) {
fprintf(stderr, "Fail to discover characteristics.\n");
return 1;
@ -245,6 +247,7 @@ done:
#endif
int gattlib_discover_desc_range(gatt_connection_t* connection, int start, int end, gattlib_descriptor_t** descriptors, int* descriptor_count) {
gattlib_context_t* conn_context = connection->context;
struct descriptor_cb_t descriptor_data;
guint ret;
@ -253,7 +256,7 @@ int gattlib_discover_desc_range(gatt_connection_t* connection, int start, int en
#if BLUEZ_VERSION_MAJOR == 4
ret = gatt_find_info(connection->attrib, start, end, char_desc_cb, &descriptor_data);
#else
ret = gatt_discover_desc(connection->attrib, start, end, NULL, char_desc_cb, &descriptor_data);
ret = gatt_discover_desc(conn_context->attrib, start, end, NULL, char_desc_cb, &descriptor_data);
#endif
if (ret == 0) {
fprintf(stderr, "Fail to discover descriptors.\n");

View File

@ -45,6 +45,15 @@ struct gattlib_thread_t {
GMainLoop* loop;
};
typedef struct {
GIOChannel* io;
GAttrib* attrib;
// We keep a list of characteristics to make the correspondence handle/UUID.
gattlib_characteristic_t* characteristics;
int characteristic_count;
} gattlib_context_t;
extern struct gattlib_thread_t g_gattlib_thread;
/**

View File

@ -97,6 +97,7 @@ void uuid_to_bt_uuid(uuid_t* uuid, bt_uuid_t* bt_uuid) {
int gattlib_read_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid,
void* buffer, size_t buffer_len)
{
gattlib_context_t* conn_context = connection->context;
struct gattlib_result_read_uuid_t* gattlib_result;
bt_uuid_t bt_uuid;
const int start = 0x0001;
@ -115,7 +116,7 @@ int gattlib_read_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid,
uuid_to_bt_uuid(uuid, &bt_uuid);
gatt_read_char_by_uuid(connection->attrib, start, end, &bt_uuid,
gatt_read_char_by_uuid(conn_context->attrib, start, end, &bt_uuid,
gattlib_result_read_uuid_cb, gattlib_result);
// Wait for completion of the event
@ -132,6 +133,7 @@ int gattlib_read_char_by_uuid(gatt_connection_t* connection, uuid_t* uuid,
int gattlib_read_char_by_uuid_async(gatt_connection_t* connection, uuid_t* uuid,
gatt_read_cb_t gatt_read_cb)
{
gattlib_context_t* conn_context = connection->context;
struct gattlib_result_read_uuid_t* gattlib_result;
const int start = 0x0001;
const int end = 0xffff;
@ -149,7 +151,7 @@ int gattlib_read_char_by_uuid_async(gatt_connection_t* connection, uuid_t* uuid,
uuid_to_bt_uuid(uuid, &bt_uuid);
guint id = gatt_read_char_by_uuid(connection->attrib, start, end, &bt_uuid,
guint id = gatt_read_char_by_uuid(conn_context->attrib, start, end, &bt_uuid,
gattlib_result_read_uuid_cb, gattlib_result);
if (id) {
@ -166,9 +168,10 @@ void gattlib_write_result_cb(guint8 status, const guint8 *pdu, guint16 len, gpoi
}
int gattlib_write_char_by_handle(gatt_connection_t* connection, uint16_t handle, void* buffer, size_t buffer_len) {
gattlib_context_t* conn_context = connection->context;
int write_completed = FALSE;
guint ret = gatt_write_char(connection->attrib, handle, buffer, buffer_len,
guint ret = gatt_write_char(conn_context->attrib, handle, buffer, buffer_len,
gattlib_write_result_cb, &write_completed);
if (ret == 0) {
return 1;

View File

@ -230,9 +230,16 @@ gatt_connection_t *gattlib_connect(const char *src, const char *dst,
// Generate object path like: /org/bluez/hci0/dev_DA_94_40_95_E0_87
snprintf(object_path, sizeof(object_path), "/org/bluez/%s/dev_%s", adapter_name, device_address_str);
gattlib_context_t* conn_context = calloc(sizeof(gattlib_context_t), 1);
if (conn_context == NULL) {
return NULL;
}
gatt_connection_t* connection = calloc(sizeof(gatt_connection_t), 1);
if (connection == NULL) {
return NULL;
} else {
connection->context = conn_context;
}
OrgBluezDevice1* device = org_bluez_device1_proxy_new_for_bus_sync(
@ -245,7 +252,8 @@ gatt_connection_t *gattlib_connect(const char *src, const char *dst,
if (device == NULL) {
goto FREE_CONNECTION;
} else {
connection->io = device;
conn_context->device = device;
conn_context->device_object_path = strdup(object_path);
}
error = NULL;
@ -272,7 +280,8 @@ gatt_connection_t *gattlib_connect(const char *src, const char *dst,
return connection;
FREE_DEVICE:
g_object_unref(connection->io);
free(conn_context->device_object_path);
g_object_unref(conn_context->device);
FREE_CONNECTION:
free(connection);
@ -287,7 +296,15 @@ gatt_connection_t *gattlib_connect_async(const char *src, const char *dst,
}
int gattlib_disconnect(gatt_connection_t* connection) {
g_object_unref(connection->io);
gattlib_context_t* conn_context = connection->context;
GError *error = NULL;
org_bluez_device1_call_disconnect_sync(conn_context->device, NULL, &error);
free(conn_context->device_object_path);
g_object_unref(conn_context->device);
free(connection->context);
free(connection);
return 0;
}
@ -295,6 +312,7 @@ int gattlib_disconnect(gatt_connection_t* connection) {
// Bluez was using org.bluez.Device1.GattServices until 5.37 to expose the list of available GATT Services
#if BLUEZ_VERSION < BLUEZ_VERSIONS(5, 38)
int gattlib_discover_primary(gatt_connection_t* connection, gattlib_primary_service_t** services, int* services_count) {
gattlib_context_t* conn_context = connection->context;
OrgBluezDevice1* device = conn_context->device;
const gchar* const* service_str;
GError *error = NULL;
@ -445,6 +463,7 @@ int gattlib_discover_char_range(gatt_connection_t* connection, int start, int en
// Bluez was using org.bluez.Device1.GattServices until 5.37 to expose the list of available GATT Services
#if BLUEZ_VERSION < BLUEZ_VERSIONS(5, 38)
int gattlib_discover_char(gatt_connection_t* connection, gattlib_characteristic_t** characteristics, int* characteristic_count) {
gattlib_context_t* conn_context = connection->context;
OrgBluezDevice1* device = conn_context->device;
GError *error = NULL;

View File

@ -37,4 +37,9 @@
#define BLUEZ_VERSIONS(major, minor) (((major) << 8) | (minor))
#define BLUEZ_VERSION BLUEZ_VERSIONS(BLUEZ_VERSION_MAJOR, BLUEZ_VERSION_MINOR)
typedef struct {
char* device_object_path;
OrgBluezDevice1* device;
} gattlib_context_t;
#endif

View File

@ -143,7 +143,8 @@ done:
static gboolean primary(gpointer user_data)
{
gatt_connection_t* connection = (gatt_connection_t*)user_data;
GAttrib *attrib = connection->attrib;
gattlib_context_t* conn_context = connection->context;
GAttrib *attrib = conn_context->attrib;
char uuid_str[MAX_LEN_UUID_STR + 1];
if (opt_uuid)
@ -238,7 +239,8 @@ static void bt_uuid_to_uuid(bt_uuid_t* bt_uuid, uuid_t* uuid) {
static gboolean characteristics_read(gpointer user_data)
{
gatt_connection_t* connection = (gatt_connection_t*)user_data;
GAttrib *attrib = connection->attrib;
gattlib_context_t* conn_context = connection->context;
GAttrib *attrib = conn_context->attrib;
if (opt_uuid != NULL) {
uint8_t buffer[0x100];
@ -286,7 +288,8 @@ static void mainloop_quit(gpointer user_data)
static gboolean characteristics_write(gpointer user_data)
{
GAttrib *attrib = ((gatt_connection_t*)user_data)->attrib;
gattlib_context_t* conn_context = ((gatt_connection_t*)user_data)->context;
GAttrib *attrib = conn_context->attrib;
uint8_t *value;
size_t len;
@ -343,7 +346,8 @@ done:
static gboolean characteristics_write_req(gpointer user_data)
{
GAttrib *attrib = ((gatt_connection_t*)user_data)->attrib;
gattlib_context_t* conn_context = ((gatt_connection_t*)user_data)->context;
GAttrib *attrib = conn_context->attrib;
uint8_t *value;
size_t len;

View File

@ -31,3 +31,12 @@ int interactive(const gchar *src, const gchar *dst, const gchar *dst_type,
size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
uint8_t get_dest_type_from_str(const char* dst_type);
BtIOSecLevel get_sec_level_from_str(const char* sec_level);
typedef struct {
GIOChannel* io;
GAttrib* attrib;
// We keep a list of characteristics to make the correspondence handle/UUID.
gattlib_characteristic_t* characteristics;
int characteristic_count;
} gattlib_context_t;

View File

@ -305,10 +305,12 @@ static void cmd_connect(int argcp, char **argvp)
sec_level = get_sec_level_from_str(opt_sec_level);
connection = gattlib_connect_async(opt_src, opt_dst, dst_type, sec_level,
opt_psm, opt_mtu, connect_cb);
if (connection == NULL)
if (connection == NULL) {
set_state(STATE_DISCONNECTED);
else
g_io_add_watch(g_connection->io, G_IO_HUP, channel_watcher, NULL);
} else {
gattlib_context_t* conn_context = g_connection->context;
g_io_add_watch(conn_context->io, G_IO_HUP, channel_watcher, NULL);
}
}
static void cmd_disconnect(int argcp, char **argvp)
@ -318,6 +320,7 @@ static void cmd_disconnect(int argcp, char **argvp)
static void cmd_primary(int argcp, char **argvp)
{
gattlib_context_t* conn_context = g_connection->context;
bt_uuid_t uuid;
if (conn_state != STATE_CONNECTED) {
@ -349,7 +352,7 @@ static void cmd_primary(int argcp, char **argvp)
return;
}
gatt_discover_primary(g_connection->attrib, &uuid, primary_by_uuid_cb, NULL);
gatt_discover_primary(conn_context->attrib, &uuid, primary_by_uuid_cb, NULL);
}
static int strtohandle(const char *src)
@ -367,6 +370,7 @@ static int strtohandle(const char *src)
static void cmd_char(int argcp, char **argvp)
{
gattlib_context_t* conn_context = g_connection->context;
char uuid_str[MAX_LEN_UUID_STR + 1];
gattlib_characteristic_t* characteristics;
int characteristics_count, ret, i;
@ -402,7 +406,7 @@ static void cmd_char(int argcp, char **argvp)
return;
}
gatt_discover_char(g_connection->attrib, start, end, &uuid, char_cb, NULL);
gatt_discover_char(conn_context->attrib, start, end, &uuid, char_cb, NULL);
return;
}
@ -462,6 +466,7 @@ static void cmd_char_desc(int argcp, char **argvp)
static void cmd_read_hnd(int argcp, char **argvp)
{
gattlib_context_t* conn_context = g_connection->context;
int handle;
if (conn_state != STATE_CONNECTED) {
@ -495,15 +500,16 @@ static void cmd_read_hnd(int argcp, char **argvp)
}
#endif
gatt_read_char(g_connection->attrib, handle,
gatt_read_char(conn_context->attrib, handle,
#if BLUEZ_VERSION_MAJOR == 4
offset,
#endif
char_read_cb, g_connection->attrib);
char_read_cb, conn_context->attrib);
}
static void cmd_read_uuid(int argcp, char **argvp)
{
gattlib_context_t* conn_context = g_connection->context;
struct characteristic_data *char_data;
int start = 0x0001;
int end = 0xffff;
@ -546,7 +552,7 @@ static void cmd_read_uuid(int argcp, char **argvp)
char_data->end = end;
char_data->uuid = uuid;
gatt_read_char_by_uuid(g_connection->attrib, start, end, &char_data->uuid,
gatt_read_char_by_uuid(conn_context->attrib, start, end, &char_data->uuid,
char_read_by_uuid_cb, char_data);
}
@ -569,6 +575,7 @@ static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
static void cmd_char_write(int argcp, char **argvp)
{
gattlib_context_t* conn_context = g_connection->context;
uint8_t *value;
size_t plen;
int handle;
@ -596,16 +603,17 @@ static void cmd_char_write(int argcp, char **argvp)
}
if (g_strcmp0("char-write-req", argvp[0]) == 0)
gatt_write_char(g_connection->attrib, handle, value, plen,
gatt_write_char(conn_context->attrib, handle, value, plen,
char_write_req_cb, NULL);
else
gatt_write_char(g_connection->attrib, handle, value, plen, NULL, NULL);
gatt_write_char(conn_context->attrib, handle, value, plen, NULL, NULL);
g_free(value);
}
static void cmd_sec_level(int argcp, char **argvp)
{
gattlib_context_t* conn_context = g_connection->context;
GError *gerr = NULL;
BtIOSecLevel sec_level;
@ -636,7 +644,7 @@ static void cmd_sec_level(int argcp, char **argvp)
return;
}
bt_io_set(g_connection->io,
bt_io_set(conn_context->io,
#if BLUEZ_VERSION_MAJOR == 4
BT_IO_L2CAP,
#endif
@ -653,6 +661,7 @@ static void cmd_sec_level(int argcp, char **argvp)
static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
gattlib_context_t* conn_context = g_connection->context;
uint16_t mtu;
if (status != 0) {
@ -668,7 +677,7 @@ static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
mtu = MIN(mtu, opt_mtu);
/* Set new value for MTU in client */
if (g_attrib_set_mtu(g_connection->attrib, mtu))
if (g_attrib_set_mtu(conn_context->attrib, mtu))
printf("MTU was exchanged successfully: %d\n", mtu);
else
printf("Error exchanging MTU\n");
@ -676,6 +685,8 @@ static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
static void cmd_mtu(int argcp, char **argvp)
{
gattlib_context_t* conn_context = g_connection->context;
if (conn_state != STATE_CONNECTED) {
printf("Command failed: not connected.\n");
return;
@ -706,7 +717,7 @@ static void cmd_mtu(int argcp, char **argvp)
return;
}
gatt_exchange_mtu(g_connection->attrib, opt_mtu, exchange_mtu_cb, NULL);
gatt_exchange_mtu(conn_context->attrib, opt_mtu, exchange_mtu_cb, NULL);
}
static struct {

View File

@ -68,9 +68,7 @@ typedef struct _GAttrib GAttrib;
typedef void (*gattlib_event_handler_t)(uint16_t handle, const uint8_t* data, size_t data_length, void* user_data);
typedef struct _gatt_connection_t {
void *io; // Mapped to 'GIOChannel*' when using Glib
GAttrib *attrib;
void* context;
gattlib_event_handler_t notification_handler;
void* notification_user_data;