From 158be024daa1d753a867d7eadd4a08740e2afde1 Mon Sep 17 00:00:00 2001 From: Seungyoun Ju Date: Fri, 2 Dec 2016 19:02:42 +0900 Subject: [PATCH] Process response_needed parameter in GATT Server [Model] COMMON [BinType] AP [Customer] OPEN [Issue#] N/A [Request] Internal [Occurrence Version] N/A [Problem] User couldn't know whether this write request require a response or not [Cause & Measure] Old bluez didn't provide the information about response's necessity. Now bluez provides it so processing logic has been implemented in this patch. [Checking Method] Run GATT Server on DUT -> Send some Write Without Response or Write Req from remote [Team] Basic connection [Developer] Seungyoun Ju [Solution company] Samsung [Change Type] Specification change Change-Id: If519f964c86f7c786b92febc1104358184aef427 --- bt-api/bt-gatt-service.c | 391 ++++++++++++++++++++++++++--------------------- include/bluetooth-api.h | 4 +- 2 files changed, 222 insertions(+), 173 deletions(-) diff --git a/bt-api/bt-gatt-service.c b/bt-api/bt-gatt-service.c index 3a5659c..50957ba 100644 --- a/bt-api/bt-gatt-service.c +++ b/bt-api/bt-gatt-service.c @@ -60,14 +60,15 @@ static const gchar characteristics_introspection_xml[] = " " " " " " -" " +" " " " " " " " " " " " -" " +" " " " +" " " " " " " " @@ -103,14 +104,15 @@ static const gchar descriptor_introspection_xml[] = " " " " " " -" " +" " " " " " " " " " " " -" " +" " " " +" " " " " " " " @@ -632,74 +634,72 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, if (g_strcmp0(method_name, "ReadValue") == 0) { gchar *addr = NULL; - guint8 req_id = 1; + guint req_id = 0; guint16 offset = 0; bt_gatt_read_req_t read_req = {0, }; bt_user_info_t *user_info = NULL; struct gatt_req_info *req_info = NULL; struct gatt_service_info *svc_info = NULL; - - BT_DBG("ReadValue"); - - g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset); +#ifdef TIZEN_FEATURE_BT_HPS + GVariant *param = NULL; +#endif BT_DBG("Application path = %s", object_path); + BT_DBG("Sender = %s", sender); - BT_DBG("Remote Device address number = %s", addr); - BT_DBG("Request id = %d, Offset = %d", req_id, offset); + user_info = _bt_get_user_data(BT_COMMON); + if (user_info == NULL) { + BT_INFO("No callback is set for %s", object_path); + g_dbus_method_invocation_return_value(invocation, NULL); + return; + } - BT_DBG("Sender = %s", sender); + svc_info = __bt_gatt_find_gatt_service_from_char(object_path); + if (svc_info == NULL) { + BT_ERR("Coudn't find service for %s", object_path); + g_dbus_method_invocation_return_value(invocation, NULL); + return; + } - read_req.att_handle = g_strdup(object_path); - read_req.address = g_strdup(addr); + g_variant_get(parameters, "(&suq)", &addr, &req_id, &offset); + BT_DBG("Request id = %u, Offset = %u", req_id, offset); + + read_req.att_handle = (char *)object_path; + read_req.address = addr; read_req.req_id = req_id; read_req.offset = offset; - svc_info = __bt_gatt_find_gatt_service_from_char(object_path); - if (svc_info != NULL) { - read_req.service_handle = g_strdup(svc_info->serv_path); - user_info = _bt_get_user_data(BT_COMMON); -#ifdef TIZEN_FEATURE_BT_HPS - GVariant *param = NULL; -#endif + read_req.service_handle = svc_info->serv_path; - /* Store requets information */ - req_info = g_new0(struct gatt_req_info, 1); - req_info->attr_path = g_strdup(object_path); - req_info->svc_path = g_strdup(read_req.service_handle); - req_info->request_id = req_id; - req_info->offset = offset; - req_info->context = invocation; - gatt_requests = g_slist_append(gatt_requests, req_info); + /* Store requets information */ + req_info = g_new0(struct gatt_req_info, 1); + req_info->attr_path = g_strdup(object_path); + req_info->svc_path = g_strdup(read_req.service_handle); + req_info->request_id = req_id; + req_info->offset = offset; + req_info->context = invocation; + gatt_requests = g_slist_append(gatt_requests, req_info); - if (user_info != NULL) { - _bt_common_event_cb( - BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, BLUETOOTH_ERROR_NONE, &read_req, user_info->cb, user_info->user_data); - } + #ifdef TIZEN_FEATURE_BT_HPS - param = g_variant_new("(sssyq)", - read_req.att_handle, - read_req.service_handle, - read_req.address, - read_req.req_id, - read_req.offset); - __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, param); + param = g_variant_new("(sssyq)", + read_req.att_handle, + read_req.service_handle, + read_req.address, + read_req.req_id, + read_req.offset); + __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, param); #endif - } - if (read_req.att_handle) - g_free(read_req.att_handle); - if (read_req.address) - g_free(read_req.address); - if (read_req.service_handle) - g_free(read_req.service_handle); return; } else if (g_strcmp0(method_name, "WriteValue") == 0) { GVariant *var = NULL; gchar *addr = NULL; - guint8 req_id = 0; + guint req_id = 0; guint16 offset = 0; + gboolean response_needed = FALSE; bt_gatt_value_change_t value_change = {0, }; bt_user_info_t *user_info = NULL; int len = 0; @@ -713,55 +713,77 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, BT_DBG("Application path = %s", object_path); BT_DBG("Sender = %s", sender); - g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var); + g_variant_get(parameters, "(&suqb@ay)", + &addr, &req_id, &offset, &response_needed, &var); + BT_DBG("Request id = %u, Offset = %u", req_id, offset); + + user_info = _bt_get_user_data(BT_COMMON); + if (!user_info) { + BT_INFO("No callback is set for %s", object_path); + g_variant_unref(var); + if (response_needed) + g_dbus_method_invocation_return_value(invocation, NULL); + else + g_object_unref (invocation); + return; + } - value_change.att_handle = g_strdup(object_path); - value_change.address = g_strdup(addr); svc_info = __bt_gatt_find_gatt_service_from_char(object_path); if (svc_info == NULL) { + BT_ERR("Coudn't find service for %s", object_path); g_variant_unref(var); - g_dbus_method_invocation_return_value(invocation, NULL); + if (response_needed) + g_dbus_method_invocation_return_value(invocation, NULL); + else + g_object_unref (invocation); return; } - value_change.service_handle = g_strdup(svc_info->serv_path); + value_change.att_handle = (char *)object_path; + value_change.address = addr; + value_change.service_handle = svc_info->serv_path; value_change.offset = offset; value_change.req_id = req_id; + value_change.response_needed = response_needed; len = g_variant_get_size(var); if (len > 0) { char *data; - value_change.att_value = (guint8 *)malloc(len); + value_change.att_value = (guint8 *)g_malloc(len); if (!value_change.att_value) { BT_ERR("att_value is NULL"); g_variant_unref(var); - g_dbus_method_invocation_return_value(invocation, NULL); + if (response_needed) + g_dbus_method_invocation_return_value(invocation, NULL); + else + g_object_unref (invocation); return; } data = (char *)g_variant_get_data(var); memcpy(value_change.att_value, data, len); } - value_change.val_len = len; - /* Store requets information */ - req_info = g_new0(struct gatt_req_info, 1); - req_info->attr_path = g_strdup(object_path); - req_info->svc_path = g_strdup(value_change.service_handle); - req_info->request_id = req_id; - req_info->offset = offset; - req_info->context = invocation; - gatt_requests = g_slist_append(gatt_requests, req_info); - - user_info = _bt_get_user_data(BT_COMMON); - if (user_info != NULL) { - _bt_common_event_cb( - BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, - BLUETOOTH_ERROR_NONE, &value_change, - user_info->cb, user_info->user_data); + if (response_needed) { + /* Store requets information */ + req_info = g_new0(struct gatt_req_info, 1); + req_info->attr_path = g_strdup(object_path); + req_info->svc_path = g_strdup(value_change.service_handle); + req_info->request_id = req_id; + req_info->offset = offset; + req_info->context = invocation; + gatt_requests = g_slist_append(gatt_requests, req_info); + } else { + g_object_unref (invocation); } + + _bt_common_event_cb( + BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, + BLUETOOTH_ERROR_NONE, &value_change, + user_info->cb, user_info->user_data); + #ifdef TIZEN_FEATURE_BT_HPS if (len > 0) { gchar *svc_path; @@ -778,6 +800,8 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, g_free(svc_path); } #endif + + g_free(value_change.att_value); g_variant_unref(var); return; } else if (g_strcmp0(method_name, "StartNotify") == 0) { @@ -789,8 +813,8 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, struct gatt_service_info *svc_info = NULL; svc_info = __bt_gatt_find_gatt_service_from_char(object_path); if (svc_info) { - notify_change.service_handle = g_strdup(svc_info->serv_path); - notify_change.att_handle = g_strdup(object_path); + notify_change.service_handle = svc_info->serv_path; + notify_change.att_handle = (char *)object_path; notify_change.att_notify = TRUE; _bt_common_event_cb( BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED, @@ -807,8 +831,8 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, struct gatt_service_info *svc_info = NULL; svc_info = __bt_gatt_find_gatt_service_from_char(object_path); if (svc_info) { - notify_change.service_handle = g_strdup(svc_info->serv_path); - notify_change.att_handle = g_strdup(object_path); + notify_change.service_handle = svc_info->serv_path; + notify_change.att_handle = (char *)object_path; notify_change.att_notify = FALSE; _bt_common_event_cb( BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED, @@ -820,7 +844,7 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, gchar *addr = NULL; bt_gatt_indicate_confirm_t confirm = {0, }; bt_user_info_t *user_info = NULL; - gboolean complete = 0; + gboolean complete = FALSE; struct gatt_service_info *svc_info = NULL; BT_DBG("IndicateConfirm"); @@ -828,17 +852,17 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, BT_DBG("Sender = %s", sender); g_variant_get(parameters, "(&sb)", &addr, &complete); - BT_DBG("Remote Device address number = %s", addr); - confirm.att_handle = g_strdup(object_path); - confirm.address = g_strdup(addr); + + confirm.att_handle = (char *)object_path; + confirm.address = addr; confirm.complete = complete; svc_info = __bt_gatt_find_gatt_service_from_char(object_path); if (svc_info != NULL) { - confirm.service_handle = g_strdup(svc_info->serv_path); - user_info = _bt_get_user_data(BT_COMMON); + confirm.service_handle = svc_info->serv_path; + user_info = _bt_get_user_data(BT_COMMON); if (user_info != NULL) { _bt_common_event_cb( BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_COMPLETED, @@ -847,6 +871,7 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, } } } + g_dbus_method_invocation_return_value(invocation, NULL); } @@ -861,62 +886,61 @@ static void __bt_gatt_desc_method_call(GDBusConnection *connection, { if (g_strcmp0(method_name, "ReadValue") == 0) { gchar *addr = NULL; - guint8 req_id = 1; + guint req_id = 0; guint16 offset = 0; bt_gatt_read_req_t read_req = {0, }; bt_user_info_t *user_info = NULL; struct gatt_req_info *req_info = NULL; struct gatt_service_info *svc_info = NULL; - BT_DBG("ReadValue"); - - g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset); + BT_DBG("ReadValue"); BT_DBG("Application path = %s", object_path); + BT_DBG("Sender = %s", sender); - BT_DBG("Remote Device address number = %s", addr); - BT_DBG("Request id = %d, Offset = %d", req_id, offset); + user_info = _bt_get_user_data(BT_COMMON); + if (user_info == NULL) { + BT_INFO("No callback is set for %s", object_path); + g_dbus_method_invocation_return_value(invocation, NULL); + return; + } - BT_DBG("Sender = %s", sender); + svc_info = __bt_gatt_find_gatt_service_from_desc(object_path); + if (svc_info == NULL) { + BT_ERR("Coudn't find service for %s", object_path); + g_dbus_method_invocation_return_value(invocation, NULL); + return; + } + + g_variant_get(parameters, "(&suq)", &addr, &req_id, &offset); + BT_DBG("Request id = %u, Offset = %u", req_id, offset); - read_req.att_handle = g_strdup(object_path); - read_req.address = g_strdup(addr); + read_req.att_handle = (char *)object_path; + read_req.address = addr; read_req.req_id = req_id; read_req.offset = offset; - svc_info = __bt_gatt_find_gatt_service_from_desc(object_path); - if (svc_info != NULL) { - read_req.service_handle = g_strdup(svc_info->serv_path); - user_info = _bt_get_user_data(BT_COMMON); + read_req.service_handle = svc_info->serv_path; - /* Store requets information */ - req_info = g_new0(struct gatt_req_info, 1); - req_info->attr_path = g_strdup(object_path); - req_info->svc_path = g_strdup(read_req.service_handle); - req_info->request_id = req_id; - req_info->offset = offset; - req_info->context = invocation; - gatt_requests = g_slist_append(gatt_requests, req_info); - - if (user_info != NULL) { - _bt_common_event_cb( - BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, - BLUETOOTH_ERROR_NONE, &read_req, - user_info->cb, user_info->user_data); - } - } + /* Store requets information */ + req_info = g_new0(struct gatt_req_info, 1); + req_info->attr_path = g_strdup(object_path); + req_info->svc_path = g_strdup(read_req.service_handle); + req_info->request_id = req_id; + req_info->offset = offset; + req_info->context = invocation; + gatt_requests = g_slist_append(gatt_requests, req_info); - if (read_req.att_handle) - g_free(read_req.att_handle); - if (read_req.address) - g_free(read_req.address); - if (read_req.service_handle) - g_free(read_req.service_handle); + _bt_common_event_cb( + BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, + BLUETOOTH_ERROR_NONE, &read_req, + user_info->cb, user_info->user_data); return; } else if (g_strcmp0(method_name, "WriteValue") == 0) { GVariant *var = NULL; gchar *addr = NULL; - guint8 req_id = 0; + guint req_id = 0; guint16 offset = 0; + gboolean response_needed = FALSE; bt_gatt_value_change_t value_change = {0, }; bt_user_info_t *user_info = NULL; int len = 0; @@ -927,58 +951,80 @@ static void __bt_gatt_desc_method_call(GDBusConnection *connection, BT_DBG("Application path = %s", object_path); BT_DBG("Sender = %s", sender); - g_variant_get(parameters, "(&syq@ay)", &addr, &req_id, &offset, &var); + g_variant_get(parameters, "(&suqb@ay)", + &addr, &req_id, &offset, &response_needed, &var); + BT_DBG("Request id = %u, Offset = %u", req_id, offset); + + user_info = _bt_get_user_data(BT_COMMON); + if (user_info == NULL) { + BT_INFO("No callback is set for %s", object_path); + g_variant_unref(var); + if (response_needed) + g_dbus_method_invocation_return_value(invocation, NULL); + else + g_object_unref (invocation); + return; + } - value_change.att_handle = g_strdup(object_path); - value_change.address = g_strdup(addr); svc_info = __bt_gatt_find_gatt_service_from_desc(object_path); if (svc_info == NULL) { + BT_ERR("Coudn't find service for %s", object_path); g_variant_unref(var); - g_dbus_method_invocation_return_value(invocation, NULL); + if (response_needed) + g_dbus_method_invocation_return_value(invocation, NULL); + else + g_object_unref (invocation); return; } - value_change.service_handle = g_strdup(svc_info->serv_path); + value_change.att_handle = (char *)object_path; + value_change.address = addr; + value_change.service_handle = svc_info->serv_path; value_change.offset = offset; value_change.req_id = req_id; + value_change.response_needed = response_needed; len = g_variant_get_size(var); if (len > 0) { char *data; - value_change.att_value = (guint8 *)malloc(len); + value_change.att_value = (guint8 *)g_malloc(len); if (!value_change.att_value) { BT_ERR("att_value is NULL"); g_variant_unref(var); - g_dbus_method_invocation_return_value(invocation, NULL); + if (response_needed) + g_dbus_method_invocation_return_value(invocation, NULL); + else + g_object_unref (invocation); return; } data = (char *)g_variant_get_data(var); memcpy(value_change.att_value, data, len); } - g_variant_unref(var); - value_change.val_len = len; - /* Store requets information */ - req_info = g_new0(struct gatt_req_info, 1); - req_info->attr_path = g_strdup(object_path); - req_info->svc_path = g_strdup(value_change.service_handle); - req_info->request_id = req_id; - req_info->offset = offset; - req_info->context = invocation; - gatt_requests = g_slist_append(gatt_requests, req_info); - - user_info = _bt_get_user_data(BT_COMMON); - if (user_info != NULL) { - _bt_common_event_cb( - BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, - BLUETOOTH_ERROR_NONE, &value_change, - user_info->cb, user_info->user_data); + if (response_needed) { + /* Store requets information */ + req_info = g_new0(struct gatt_req_info, 1); + req_info->attr_path = g_strdup(object_path); + req_info->svc_path = g_strdup(value_change.service_handle); + req_info->request_id = req_id; + req_info->offset = offset; + req_info->context = invocation; + gatt_requests = g_slist_append(gatt_requests, req_info); + } else { + g_object_unref (invocation); } + + _bt_common_event_cb( + BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, + BLUETOOTH_ERROR_NONE, &value_change, + user_info->cb, user_info->user_data); + + g_free(value_change.att_value); + g_variant_unref(var); return; } - g_dbus_method_invocation_return_value(invocation, NULL); } gboolean __bt_gatt_emit_interface_removed(gchar *object_path, gchar *interface) @@ -2458,37 +2504,17 @@ BT_EXPORT_API int bluetooth_gatt_send_response(int request_id, guint req_type, } req_info = __bt_gatt_find_request_info(request_id); + if (req_info == NULL) { + BT_ERR("Coundn't find request id [%d]", request_id); + return BLUETOOTH_ERROR_INTERNAL; + } - if (req_info) { - if (resp_state != BLUETOOTH_ERROR_NONE) { - g_dbus_method_invocation_return_dbus_error(req_info->context, - "org.bluez.Error.Failed", "Application Error"); - - gatt_requests = g_slist_remove(gatt_requests, req_info); + if (resp_state != BLUETOOTH_ERROR_NONE) { + BT_ERR("resp_state is 0x%X", resp_state); - req_info->context = NULL; - if (req_info->attr_path) - g_free(req_info->attr_path); - if (req_info->svc_path) - g_free(req_info->svc_path); - g_free(req_info); + g_dbus_method_invocation_return_dbus_error(req_info->context, + "org.bluez.Error.Failed", "Application Error"); - return BLUETOOTH_ERROR_NONE; - } - if (req_type == BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ) { - int i; - GVariantBuilder *inner_builder = NULL; - inner_builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); - if (value_length > 0 && value != NULL) { - for (i = 0; i < value_length; i++) - g_variant_builder_add(inner_builder, "y", value[i]); - } - g_dbus_method_invocation_return_value(req_info->context, - g_variant_new("(ay)", inner_builder)); - g_variant_builder_unref(inner_builder); - } else { - g_dbus_method_invocation_return_value(req_info->context, NULL); - } gatt_requests = g_slist_remove(gatt_requests, req_info); req_info->context = NULL; @@ -2497,9 +2523,32 @@ BT_EXPORT_API int bluetooth_gatt_send_response(int request_id, guint req_type, if (req_info->svc_path) g_free(req_info->svc_path); g_free(req_info); + + return BLUETOOTH_ERROR_NONE; + } + + if (req_type == BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ) { + int i; + GVariantBuilder *inner_builder = NULL; + inner_builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); + if (value_length > 0 && value != NULL) { + for (i = 0; i < value_length; i++) + g_variant_builder_add(inner_builder, "y", value[i]); + } + g_dbus_method_invocation_return_value(req_info->context, + g_variant_new("(ay)", inner_builder)); + g_variant_builder_unref(inner_builder); } else { - return BLUETOOTH_ERROR_INTERNAL; + g_dbus_method_invocation_return_value(req_info->context, NULL); } + gatt_requests = g_slist_remove(gatt_requests, req_info); + + req_info->context = NULL; + if (req_info->attr_path) + g_free(req_info->attr_path); + if (req_info->svc_path) + g_free(req_info->svc_path); + g_free(req_info); return BLUETOOTH_ERROR_NONE; } diff --git a/include/bluetooth-api.h b/include/bluetooth-api.h index 8129a1c..c50657c 100644 --- a/include/bluetooth-api.h +++ b/include/bluetooth-api.h @@ -1399,7 +1399,7 @@ typedef struct { char *service_handle; char *address; guint16 offset; - guint8 req_id; + guint req_id; } bt_gatt_read_req_t; /** @@ -1409,7 +1409,7 @@ typedef struct { char *att_handle; char *service_handle; char *address; - guint8 req_id; + guint req_id; gboolean response_needed; guint16 offset; guint8 *att_value; -- 2.7.4