X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-api%2Fbt-gatt-service.c;h=8e554405eaf9a0f7ce26f41d31eb229a0519599b;hb=721ed6156339ed0146fecfbc99ad2fcdc872190a;hp=c57397fb1d4a5064039bb5c77ce04dab6ced9ea2;hpb=449d38c6b737be52e1e166ed281bf8c778847e62;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-api/bt-gatt-service.c b/bt-api/bt-gatt-service.c old mode 100755 new mode 100644 index c57397f..8e55440 --- a/bt-api/bt-gatt-service.c +++ b/bt-api/bt-gatt-service.c @@ -21,28 +21,154 @@ #include #include #include +#include +#include +#include +#include #include "bt-common.h" +/* TODO_40 : 4.0 merge - Need to check why includes bt-event-handler.h */ +#include "bt-event-handler.h" +#include "bt-internal-types.h" + + +#include "bluetooth-gatt-server-api.h" +#include "bt-request-sender.h" +#define BT_GATT_ATT_UUID_LEN_MAX 50 +#define BT_GATT_SERVER_DBUS_NAME_LEN_MAX 50 + +static GSList *gatt_characteristic_server_notify_list = NULL;; + +/* Common defintions to follow , applicable for both + GATT_DIRECT and RELAY */ + + +#define NUMBER_OF_FLAGS 10 + + +int bluetooth_gatt_convert_prop2string( + bt_gatt_characteristic_property_t properties, + char *char_properties[]) +{ + int flag_count = 0; + + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST) { + char_properties[flag_count] = g_strdup("broadcast"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ) { + char_properties[flag_count] = g_strdup("read"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE) { + char_properties[flag_count] = g_strdup("write-without-response"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE) { + char_properties[flag_count] = g_strdup("write"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) { + char_properties[flag_count] = g_strdup("notify"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE) { + char_properties[flag_count] = g_strdup("indicate"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE) { + char_properties[flag_count] = g_strdup("authenticated-signed-writes"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE) { + char_properties[flag_count] = g_strdup("reliable-write"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES) { + char_properties[flag_count] = g_strdup("writable-auxiliaries"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ) { + char_properties[flag_count] = g_strdup("encrypt-read"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE) { + char_properties[flag_count] = g_strdup("encrypt-write"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ) { + char_properties[flag_count] = g_strdup("encrypt-authenticated-read"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE) { + char_properties[flag_count] = g_strdup("encrypt-authenticated-write"); + flag_count++; + } + + if (flag_count == 0) { + char_properties[flag_count] = g_strdup("read"); + flag_count++; + } + + return flag_count; +} + +int bluetooth_gatt_convert_perm2string( + bt_gatt_permission_t properties, + char *char_properties[]) +{ + int flag_count = 0; + + if (properties & BLUETOOTH_GATT_PERMISSION_READ) { + char_properties[flag_count] = g_strdup("read"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_PERMISSION_WRITE) { + char_properties[flag_count] = g_strdup("write"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_READ) { + char_properties[flag_count] = g_strdup("encrypt-read"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_WRITE) { + char_properties[flag_count] = g_strdup("encrypt-write"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ) { + char_properties[flag_count] = g_strdup("encrypt-authenticated-read"); + flag_count++; + } + if (properties & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE) { + char_properties[flag_count] = g_strdup("encrypt-authenticated-write"); + flag_count++; + } + + if (flag_count == 0) { + char_properties[flag_count] = g_strdup("read"); + flag_count++; + } + + return flag_count; +} + #define NUMBER_OF_FLAGS 10 -GDBusConnection *g_conn; -guint owner_id; -guint manager_id; +static GDBusConnection *g_conn; +static guint owner_id; +static guint manager_id; static gboolean new_service = FALSE; static gboolean new_char = FALSE; static int serv_id = 1; -static int register_pending_cnt = 0; +static bool is_server_started = false; + +static GCancellable *register_cancel; /* Introspection data for the service we are exporting */ static const gchar service_introspection_xml[] = "" -" " -" " -" " -" " -" " -" " +" " " " " " " " @@ -62,14 +188,15 @@ static const gchar characteristics_introspection_xml[] = " " " " " " -" " +" " " " " " " " " " " " -" " +" " " " +" " " " " " " " @@ -88,14 +215,14 @@ static const gchar characteristics_introspection_xml[] = " " " " " " -" " -" " +" " +" " " " " " " " " " -" " -" " +" " +" " " " ""; @@ -105,14 +232,15 @@ static const gchar descriptor_introspection_xml[] = " " " " " " -" " +" " " " " " " " " " " " -" " +" " " " +" " " " " " " " @@ -123,17 +251,25 @@ static const gchar descriptor_introspection_xml[] = " " " " " " -" " +" " " " " " ""; +static const gchar manager_introspection_xml[] = +"" +" " +" " +" " +" " +" " +""; + struct gatt_service_info { gchar *serv_path; guint serv_id; gchar *service_uuid; guint manager_id; - guint prop_id; GSList *char_data; gboolean is_svc_registered; gboolean is_svc_primary; @@ -155,7 +291,9 @@ struct gatt_desc_info { guint desc_id; gchar *desc_uuid; gchar *desc_value; + gchar *desc_flags[NUMBER_OF_FLAGS]; int value_length; + int flags_length; }; struct gatt_req_info { @@ -168,6 +306,7 @@ struct gatt_req_info { static GSList *gatt_services = NULL; static GSList *gatt_requests = NULL; +static gchar *app_path = NULL; #define BT_GATT_SERVICE_NAME "org.frwk.gatt_service" #define BT_GATT_SERVICE_PATH "/org/frwk/gatt_service" @@ -179,13 +318,20 @@ static GSList *gatt_requests = NULL; #define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1" #define GATT_DESC_INTERFACE "org.bluez.GattDescriptor1" -#ifdef HPS_FEATURE +#ifdef TIZEN_FEATURE_BT_HPS #define BT_HPS_OBJECT_PATH "/org/projectx/httpproxy" #define BT_HPS_INTERFACE_NAME "org.projectx.httpproxy_service" #define PROPERTIES_CHANGED "PropertiesChanged" #define BT_HPS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" #endif +#ifdef TIZEN_FEATURE_BT_OTP +#define BT_OTP_OBJECT_PATH "/org/projectx/otp" +#define BT_OTP_INTERFACE_NAME "org.projectx.otp_service" +#define PROPERTIES_CHANGED "PropertiesChanged" +#define BT_OTP_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" +#endif + static GDBusProxy *manager_gproxy = NULL; static struct gatt_char_info *__bt_gatt_find_gatt_char_info( @@ -195,8 +341,107 @@ static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info( const char *desc_path); static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id); +static int __bt_gatt_unregister_service(struct gatt_service_info *svc_info); + + + +typedef struct { + int write_fd; + int relpy_fd; + int mtu; + int att_hand; + char *path ; +} bluetooth_gatt_acquire_notify_info_t; + + +static int bluetooth_get_characteristic_fd(int att_handle , char *path) +{ + GSList *l; + + BT_DBG("request found path [%s] att_handle [ %d]", path, att_handle); + for (l = gatt_characteristic_server_notify_list; l != NULL; l = l->next) { + bluetooth_gatt_acquire_notify_info_t *info = l->data; + + if (info->att_hand == att_handle) + return info->write_fd; + } + return -1; +} + +static bluetooth_gatt_acquire_notify_info_t * bluetooth_get_characteristic_info_from_path(int att_handle) +{ + GSList *l; + + BT_DBG("request found att_handle [ %d]", att_handle); + for (l = gatt_characteristic_server_notify_list; l != NULL; l = l->next) { + bluetooth_gatt_acquire_notify_info_t *info = l->data; + BT_DBG(" sid [ %d]" , info->att_hand); + if (info->att_hand == att_handle) + return info; + } + return NULL; +} -#ifdef HPS_FEATURE + +static void bluetooth_characteristic_info_free(bluetooth_gatt_acquire_notify_info_t *chr_info) +{ + g_free(chr_info); +} + +static gboolean bluetooth_gatt_write_channel_watch_cb(GIOChannel *gio, + GIOCondition cond, gpointer data) +{ + BT_INFO("+"); + + bluetooth_gatt_acquire_notify_info_t *chr_info = (bluetooth_gatt_acquire_notify_info_t *)data; + + if (!chr_info) { + BT_INFO("chr_info is NULL"); + return FALSE; + } + + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + BT_ERR("Error : GIOCondition %d, []", cond);; + g_io_channel_shutdown(gio, TRUE, NULL); + g_io_channel_unref(gio); + + if (g_slist_find(gatt_characteristic_server_notify_list, chr_info)) { + BT_INFO("found char_info in the list"); + gatt_characteristic_server_notify_list = g_slist_remove(gatt_characteristic_server_notify_list, chr_info); + bluetooth_characteristic_info_free(chr_info); + } + + return FALSE; + } + + if (g_slist_find(gatt_characteristic_server_notify_list, chr_info) == NULL) { + BT_INFO("chr_info is not in the list"); + return FALSE; + } + + return TRUE; +} + +static int bluetooth_gatt_write_characteristics_value_to_fd_( + int fd, const guint8 *value, int length, + gpointer user_data) +{ + + int written; + int att_result = BLUETOOTH_ERROR_NONE; + + BT_CHECK_PARAMETER(value, return); + + written = write(fd, value, length); + if (written != length) { + att_result = BLUETOOTH_ERROR_INTERNAL; + BT_ERR("write data failed %d is ", written); + } + + return att_result; +} + +#ifdef TIZEN_FEATURE_BT_HPS static int __bt_send_event_to_hps(int event, GVariant *var) { GError *error = NULL; @@ -221,7 +466,7 @@ static int __bt_send_event_to_hps(int event, GVariant *var) parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder); g_variant_builder_unref(invalidated_builder); g_variant_builder_unref(inner_builder); - } else if (BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED) { + } else if (event == BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED) { GVariantBuilder *inner_builder; GVariantBuilder *invalidated_builder; @@ -235,11 +480,13 @@ static int __bt_send_event_to_hps(int event, GVariant *var) parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder); g_variant_builder_unref(invalidated_builder); g_variant_builder_unref(inner_builder); + } else { + g_varaiant_unref(var); } msg = g_dbus_message_new_signal(BT_HPS_OBJECT_PATH, BT_HPS_INTERFACE_NAME, PROPERTIES_CHANGED); g_dbus_message_set_body(msg, parameters); - if (!g_dbus_connection_send_message(g_conn, msg,G_DBUS_SEND_MESSAGE_FLAGS_NONE, 0, NULL)) { + if (!g_dbus_connection_send_message(g_conn, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 0, NULL)) { if (error != NULL) { BT_ERR("D-Bus API failure: errCode[%x], \ message[%s]", @@ -252,266 +499,285 @@ static int __bt_send_event_to_hps(int event, GVariant *var) } #endif -static void __bt_gatt_serv_method_call(GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) +#ifdef TIZEN_FEATURE_BT_OTP +static int __bt_send_event_to_otp(int event, GVariant *var) { - GSList *l1; + GError *error = NULL; + GVariant *parameters = NULL; + GDBusMessage *msg = NULL; - if (g_strcmp0(method_name, "GetManagedObjects") == 0) { - BT_DBG("Getting values for service, chars and descriptors"); + BT_DBG(" "); - GVariantBuilder *builder; - GVariantBuilder *inner_builder1 = NULL; - GVariant *svc_char = NULL; - GSList *l4; - /*Main Builder */ - builder = g_variant_builder_new( - G_VARIANT_TYPE("a{oa{sa{sv}}}")); + retv_if(g_conn == NULL, BLUETOOTH_ERROR_INTERNAL); - /* Prepare inner builder for GattService1 interface */ + if (event == BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED) { + GVariantBuilder *inner_builder; + GVariantBuilder *invalidated_builder; - GVariantBuilder *svc_builder = NULL; - GVariantBuilder *inner_builder = NULL; + BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED"); + inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); - if (register_pending_cnt > 1) { - int len = g_slist_length(gatt_services); - l1 = g_slist_nth(gatt_services, len - register_pending_cnt); - } else { - l1 = g_slist_last(gatt_services); - } - register_pending_cnt--; + g_variant_builder_add(inner_builder, "{sv}", "WriteValue", var); - struct gatt_service_info *serv_info = l1->data; - if (serv_info == NULL) { - BT_ERR("service info value is NULL"); - g_dbus_method_invocation_return_value(invocation, NULL); - return; - } + invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); - /* Prepare inner builder for GattService1 interface */ - BT_DBG("Creating builder for service"); - svc_builder = g_variant_builder_new( - G_VARIANT_TYPE("a{sa{sv}}")); + parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder); + g_variant_builder_unref(invalidated_builder); + g_variant_builder_unref(inner_builder); + } else if (event == BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED) { + GVariantBuilder *inner_builder; + GVariantBuilder *invalidated_builder; + + BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED"); inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add(inner_builder, "{sv}", "UUID", - g_variant_new_string(serv_info->service_uuid)); + g_variant_builder_add(inner_builder, "{sv}", "ReadValue", var); - g_variant_builder_add(inner_builder, "{sv}", "Primary", - g_variant_new_boolean(serv_info->is_svc_primary)); + invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); - /*Characteristics*/ - inner_builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao")); - BT_DBG("Adding Charatarisitcs list"); - for (l4 = serv_info->char_data; l4 != NULL; l4 = l4->next) { - struct gatt_char_info *char_info = l4->data; - g_variant_builder_add(inner_builder1, "o", - char_info->char_path); - BT_DBG("%s", char_info->char_path); - } + parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder); + g_variant_builder_unref(invalidated_builder); + g_variant_builder_unref(inner_builder); + } else if (event == BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED) { + GVariantBuilder *inner_builder; + GVariantBuilder *invalidated_builder; - svc_char = g_variant_new("ao", inner_builder1); - g_variant_builder_add(inner_builder, "{sv}", "Characteristics", - svc_char); + BT_DBG("BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED"); + inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add(svc_builder, "{sa{sv}}", - GATT_SERV_INTERFACE, - inner_builder); + g_variant_builder_add(inner_builder, "{sv}", "NotificationStateChanged", var); - g_variant_builder_add(builder, "{oa{sa{sv}}}", - serv_info->serv_path, - svc_builder); + invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); - g_variant_builder_unref(inner_builder1); + parameters = g_variant_new("(a{sv}as)", inner_builder, invalidated_builder); + g_variant_builder_unref(invalidated_builder); + g_variant_builder_unref(inner_builder); + } - /* Prepare inner builder for GattCharacteristic1 interface */ + msg = g_dbus_message_new_signal(BT_OTP_OBJECT_PATH, BT_OTP_INTERFACE_NAME, PROPERTIES_CHANGED); + g_dbus_message_set_body(msg, parameters); + if (!g_dbus_connection_send_message(g_conn, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 0, NULL)) { + if (error != NULL) { + BT_ERR("D-Bus API failure: errCode[%x], \ + message[%s]", + error->code, error->message); + g_clear_error(&error); + } + return BLUETOOTH_ERROR_INTERNAL; + } + return BLUETOOTH_ERROR_NONE; +} +#endif - GSList *l2 = serv_info->char_data; - BT_DBG("Creating builder for characteristics \n"); +static void __bt_gatt_manager_method_call(GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + if (g_strcmp0(method_name, "GetManagedObjects") == 0) { + BT_DBG("Getting values for service, chars and descriptors"); - if (l2 == NULL) - BT_DBG("characteristic data is NULL"); + int svc_index = 0; + GVariantBuilder *builder = NULL; + GVariantBuilder *inner_builder1 = NULL; + GVariant *svc_char = NULL; + GSList *char_list = NULL; + GSList *desc_list = NULL; - for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) { + /* Main Builder */ + builder = g_variant_builder_new(G_VARIANT_TYPE("a{oa{sa{sv}}}")); - GVariantBuilder *char_builder = NULL; + /* Prepare inner builder for GattService1 interface */ + svc_index = g_slist_length(gatt_services) - 1; + for (; svc_index >= 0; svc_index--) { + GVariantBuilder *svc_builder = NULL; GVariantBuilder *inner_builder = NULL; - GVariantBuilder *builder1 = NULL; - GVariantBuilder *builder2 = NULL; - GVariantBuilder *builder3 = NULL; - GVariant *char_val = NULL; - GVariant *flags_val = NULL; - GVariant *char_desc = NULL; - char *unicast = NULL; - gboolean notify = FALSE; - int i = 0; - - char_builder = g_variant_builder_new( - G_VARIANT_TYPE( - "a{sa{sv}}")); - inner_builder = g_variant_builder_new( - G_VARIANT_TYPE( - "a{sv}")); + struct gatt_service_info *serv_info = NULL; - struct gatt_char_info *char_info = l2->data; - if (char_info == NULL) { - BT_ERR("char_info is NULL"); + serv_info = g_slist_nth_data(gatt_services, svc_index); + if (serv_info == NULL) { + BT_ERR("serv_info is NULL"); continue; } - /*Uuid*/ + /* Prepare inner builder for GattService1 interface */ + BT_DBG("Creating builder for service : %s", serv_info->service_uuid); + svc_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}")); + inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(inner_builder, "{sv}", "UUID", - g_variant_new_string(char_info->char_uuid)); - /*Service*/ - g_variant_builder_add(inner_builder, "{sv}", "Service", - g_variant_new("o", serv_info->serv_path)); - /*Value*/ - builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); - - if(char_info->char_value != NULL) { - for (i = 0; i < char_info->value_length; i++) { - g_variant_builder_add(builder1, "y", - char_info->char_value[i]); - } - char_val = g_variant_new("ay", builder1); - g_variant_builder_add(inner_builder, "{sv}", - "Value", char_val); - } - /*Flags*/ - builder2 = g_variant_builder_new(G_VARIANT_TYPE("as")); + g_variant_new_string(serv_info->service_uuid)); + g_variant_builder_add(inner_builder, "{sv}", "Primary", + g_variant_new_boolean(serv_info->is_svc_primary)); - for (i = 0; i < char_info->flags_length; i++) { - g_variant_builder_add(builder2, "s", - char_info->char_flags[i]); + /* Characteristics */ + inner_builder1 = g_variant_builder_new(G_VARIANT_TYPE("ao")); + + BT_DBG("Adding Charatarisitcs list"); + for (char_list = serv_info->char_data; char_list != NULL; char_list = char_list->next) { + struct gatt_char_info *char_info = char_list->data; + g_variant_builder_add(inner_builder1, "o", char_info->char_path); + BT_DBG("%s", char_info->char_path); } - flags_val = g_variant_new("as", builder2); - g_variant_builder_add(inner_builder, "{sv}", "Flags", - flags_val); + svc_char = g_variant_new("ao", inner_builder1); + g_variant_builder_add(inner_builder, "{sv}", "Characteristics", svc_char); + g_variant_builder_add(svc_builder, "{sa{sv}}", GATT_SERV_INTERFACE, inner_builder); + g_variant_builder_add(builder, "{oa{sa{sv}}}", serv_info->serv_path, svc_builder); + g_variant_builder_unref(inner_builder1); - /* Notifying */ - g_variant_builder_add(inner_builder, "{sv}", "Notifying", - g_variant_new("b", notify)); + /* Prepare inner builder for GattCharacteristic1 interface */ + for (char_list = serv_info->char_data; char_list != NULL; char_list = char_list->next) { + GVariantBuilder *char_builder = NULL; + GVariantBuilder *inner_builder = NULL; + GVariantBuilder *builder1 = NULL; + GVariantBuilder *builder2 = NULL; + GVariantBuilder *builder3 = NULL; + GVariant *char_val = NULL; + GVariant *flags_val = NULL; + GVariant *char_desc = NULL; + char *unicast = NULL; + gboolean notify = FALSE; + int i = 0; + struct gatt_char_info *char_info = char_list->data; + + if (char_info == NULL) { + BT_ERR("char_info is NULL"); + continue; + } - /* Unicast */ - unicast = g_strdup("00:00:00:00:00:00"); - g_variant_builder_add(inner_builder, "{sv}", "Unicast", - g_variant_new("s", unicast)); + BT_DBG("Creating builder for characteristic : %s", char_info->char_uuid); + char_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}")); + inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); - /*Descriptors*/ - builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao")); - BT_DBG("Adding Descriptors list"); + /* UUID */ + g_variant_builder_add(inner_builder, "{sv}", "UUID", + g_variant_new_string(char_info->char_uuid)); - for (l4 = char_info->desc_data; l4 != NULL; l4 = l4->next) { - struct gatt_desc_info *desc_info = l4->data; - g_variant_builder_add(builder3, "o", - desc_info->desc_path); - BT_DBG("%s", desc_info->desc_path); - } + /* Service */ + g_variant_builder_add(inner_builder, "{sv}", "Service", + g_variant_new("o", serv_info->serv_path)); - char_desc = g_variant_new("ao", builder3); - g_variant_builder_add(inner_builder, "{sv}", "Descriptors", - char_desc); + /* Value */ + builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); + if (char_info->char_value != NULL) { + for (i = 0; i < char_info->value_length; i++) { + g_variant_builder_add(builder1, "y", char_info->char_value[i]); + } + char_val = g_variant_new("ay", builder1); + g_variant_builder_add(inner_builder, "{sv}", "Value", char_val); + } - g_variant_builder_add(char_builder, "{sa{sv}}", - GATT_CHAR_INTERFACE , inner_builder); - g_variant_builder_add(builder, "{oa{sa{sv}}}", - char_info->char_path, char_builder); + /*Flags*/ + builder2 = g_variant_builder_new(G_VARIANT_TYPE("as")); + for (i = 0; i < char_info->flags_length; i++) { + g_variant_builder_add(builder2, "s", char_info->char_flags[i]); + } + flags_val = g_variant_new("as", builder2); + g_variant_builder_add(inner_builder, "{sv}", "Flags", flags_val); + + /* Notifying */ + g_variant_builder_add(inner_builder, "{sv}", "Notifying", g_variant_new("b", notify)); + + /* Unicast */ + unicast = g_strdup("00:00:00:00:00:00"); + g_variant_builder_add(inner_builder, "{sv}", "Unicast", g_variant_new("s", unicast)); + + /*Descriptors*/ + builder3 = g_variant_builder_new(G_VARIANT_TYPE("ao")); + BT_DBG("Adding Descriptors list"); + for (desc_list = char_info->desc_data; desc_list != NULL; desc_list = desc_list->next) { + struct gatt_desc_info *desc_info = desc_list->data; + g_variant_builder_add(builder3, "o", desc_info->desc_path); + BT_DBG("%s", desc_info->desc_path); + } - /*Prepare inner builder for GattDescriptor1 interface*/ + char_desc = g_variant_new("ao", builder3); + g_variant_builder_add(inner_builder, "{sv}", "Descriptors", char_desc); + g_variant_builder_add(char_builder, "{sa{sv}}", GATT_CHAR_INTERFACE , inner_builder); + g_variant_builder_add(builder, "{oa{sa{sv}}}", char_info->char_path, char_builder); + + /*Prepare inner builder for GattDescriptor1 interface*/ + for (desc_list = char_info->desc_data; desc_list != NULL; desc_list = desc_list->next) { + GVariantBuilder *desc_builder = NULL; + GVariantBuilder *inner_builder = NULL; + GVariantBuilder *builder1 = NULL; + GVariantBuilder *builder2 = NULL; + GVariant *desc_val = NULL; + struct gatt_desc_info *desc_info = desc_list->data; + + if (desc_info == NULL) { + BT_ERR("desc_info is NULL"); + continue; + } - GSList *l3 = char_info->desc_data; + BT_DBG("Creating builder for descriptor : %s", desc_info->desc_uuid); + desc_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}")); + inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); - if (l3 == NULL) - BT_DBG("descriptor data is NULL"); + /* UUID */ + g_variant_builder_add(inner_builder, "{sv}", "UUID", + g_variant_new_string(desc_info->desc_uuid)); - for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) { + /* Characteristic */ + g_variant_builder_add(inner_builder, "{sv}", "Characteristic", + g_variant_new("o", char_info->char_path)); - BT_DBG("Creating builder for descriptor \n"); + /* Value */ + builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); + if (desc_info->desc_value != NULL) { + for (i = 0; i < desc_info->value_length; i++) { + g_variant_builder_add(builder1, "y", desc_info->desc_value[i]); + } + desc_val = g_variant_new("ay", builder1); + g_variant_builder_add(inner_builder, "{sv}", "Value", desc_val); + } - GVariantBuilder *desc_builder = NULL; - GVariantBuilder *inner_builder = NULL; - GVariantBuilder *builder1 = NULL; - GVariant *desc_val = NULL; - - desc_builder = g_variant_builder_new( - G_VARIANT_TYPE( - "a{sa{sv}}")); - inner_builder = g_variant_builder_new( - G_VARIANT_TYPE( - "a{sv}")); - - struct gatt_desc_info *desc_info = l3->data; - if (desc_info == NULL) { - BT_ERR("desc_info is NULL"); - continue; - } - - /*Uuid*/ - g_variant_builder_add(inner_builder, - "{sv}", "UUID", - g_variant_new_string( - desc_info->desc_uuid)); - - /*Characteristic*/ - g_variant_builder_add(inner_builder, "{sv}", - "Characteristic", - g_variant_new("o", - char_info->char_path)); - - /*Value*/ - builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); - - if(desc_info->desc_value != NULL) { - for (i = 0; i < desc_info->value_length; i++) { - g_variant_builder_add(builder1, "y", - desc_info->desc_value[i]); + /* Flags */ + builder2 = g_variant_builder_new(G_VARIANT_TYPE("as")); + for (i = 0; i < desc_info->flags_length; i++) { + g_variant_builder_add(builder2, "s", desc_info->desc_flags[i]); } - desc_val = g_variant_new("ay", builder1); - g_variant_builder_add(inner_builder, "{sv}", - "Value", desc_val); - } + flags_val = g_variant_new("as", builder2); + g_variant_builder_add(inner_builder, "{sv}", "Flags", flags_val); - g_variant_builder_add(desc_builder, "{sa{sv}}", - GATT_DESC_INTERFACE, - inner_builder); + g_variant_builder_add(desc_builder, "{sa{sv}}", GATT_DESC_INTERFACE, + inner_builder); + g_variant_builder_add(builder, "{oa{sa{sv}}}", desc_info->desc_path, + desc_builder); + + /* unref descriptor builder pointers */ + g_variant_builder_unref(builder1); + g_variant_builder_unref(builder2); + g_variant_builder_unref(inner_builder); + g_variant_builder_unref(desc_builder); + } - g_variant_builder_add(builder, "{oa{sa{sv}}}", - desc_info->desc_path, - desc_builder); + if (unicast) + g_free(unicast); - /*unref descriptor builder pointers*/ + /* unref char builder pointers */ g_variant_builder_unref(builder1); + g_variant_builder_unref(builder2); + g_variant_builder_unref(builder3); g_variant_builder_unref(inner_builder); - g_variant_builder_unref(desc_builder); + g_variant_builder_unref(char_builder); } - if (unicast) - g_free(unicast); - /*unref char builder pointers*/ - g_variant_builder_unref(builder1); - g_variant_builder_unref(builder2); - g_variant_builder_unref(builder3); + /* unref service builder pointers */ g_variant_builder_unref(inner_builder); - g_variant_builder_unref(char_builder); + g_variant_builder_unref(svc_builder); } - /*unref service builder pointers*/ - g_variant_builder_unref(inner_builder); - g_variant_builder_unref(svc_builder); - /* Return builder as method reply */ BT_DBG("Sending gatt service builder values to Bluez"); g_dbus_method_invocation_return_value(invocation, - g_variant_new( - "(a{oa{sa{sv}}})", - builder)); + g_variant_new("(a{oa{sa{sv}}})", builder)); + g_variant_builder_unref(builder); } } @@ -525,8 +791,7 @@ static struct gatt_service_info *__bt_gatt_find_gatt_service_from_char(const cha for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) { struct gatt_char_info *char_info = l2->data; - if (g_strcmp0(char_info->char_path, char_path) - == 0) + if (g_strcmp0(char_info->char_path, char_path) == 0) return serv_info; } } @@ -547,8 +812,7 @@ static struct gatt_service_info *__bt_gatt_find_gatt_service_from_desc(const cha for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) { struct gatt_desc_info *desc_info = l3->data; - if (g_strcmp0(desc_info->desc_path, desc_path) - == 0) + if (g_strcmp0(desc_info->desc_path, desc_path) == 0) return serv_info; } } @@ -557,29 +821,6 @@ static struct gatt_service_info *__bt_gatt_find_gatt_service_from_desc(const cha return NULL; } -static struct gatt_char_info *__bt_gatt_find_gatt_char_from_desc(const char *desc_path) -{ - GSList *l1, *l2, *l3; - - for (l1 = gatt_services; l1 != NULL; l1 = l1->next) { - struct gatt_service_info *serv_info = l1->data; - - for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) { - struct gatt_char_info *char_info = l2->data; - - for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) { - struct gatt_desc_info *desc_info = l3->data; - - if (g_strcmp0(desc_info->desc_path, desc_path) - == 0) - return char_info; - } - } - } - BT_ERR("Gatt Characterisitc not found"); - return NULL; -} - static void __bt_gatt_char_method_call(GDBusConnection *connection, const gchar *sender, const gchar *object_path, @@ -592,82 +833,82 @@ 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; - - int i; - BT_DBG("ReadValue"); - - g_variant_get(parameters, "(&syq)", &addr, &req_id, &offset); +#if defined(TIZEN_FEATURE_BT_HPS) || defined(TIZEN_FEATURE_BT_OTP) + 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 HPS_FEATURE - 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) { - struct gatt_char_info *char_info = NULL; - _bt_common_event_cb( - BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, - BLUETOOTH_ERROR_NONE, &read_req, - user_info->cb, user_info->user_data); - } -#ifdef HPS_FEATURE - 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); +#if defined(TIZEN_FEATURE_BT_HPS) || defined(TIZEN_FEATURE_BT_OTP) + param = g_variant_new("(sssyq)", + read_req.att_handle, + read_req.service_handle, + read_req.address, + read_req.req_id, + read_req.offset); +#ifdef TIZEN_FEATURE_BT_HPS + __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, param); +#endif +#ifdef TIZEN_FEATURE_BT_OTP + __bt_send_event_to_otp(BLUETOOTH_EVENT_GATT_SERVER_READ_REQUESTED, param); +#endif #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); + _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; struct gatt_service_info *svc_info = NULL; struct gatt_req_info *req_info = NULL; -#ifdef HPS_FEATURE +#if defined(TIZEN_FEATURE_BT_HPS) || defined(TIZEN_FEATURE_BT_OTP) GVariant *param = NULL; #endif @@ -675,56 +916,64 @@ 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); - if (!value_change.att_value) { - BT_ERR("att_value is NULL"); - g_variant_unref(var); - g_dbus_method_invocation_return_value(invocation, NULL); - return; - } + value_change.att_value = (guint8 *)g_malloc(len); 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); } -#ifdef HPS_FEATURE + +#if defined(TIZEN_FEATURE_BT_HPS) || defined(TIZEN_FEATURE_BT_OTP) if (len > 0) { gchar *svc_path; svc_path = g_strdup(svc_info->serv_path); @@ -735,54 +984,90 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection, req_id, offset, var); +#ifdef TIZEN_FEATURE_BT_HPS __bt_send_event_to_hps(BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, param); +#endif +#ifdef TIZEN_FEATURE_BT_OTP + __bt_send_event_to_otp(BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, param); +#endif if (svc_path) g_free(svc_path); } #endif + + _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; } else if (g_strcmp0(method_name, "StartNotify") == 0) { bt_user_info_t *user_info = NULL; bt_gatt_char_notify_change_t notify_change = {0, }; +#if TIZEN_FEATURE_BT_OTP + GVariant *param = NULL; +#endif BT_DBG("StartNotify"); user_info = _bt_get_user_data(BT_COMMON); if (user_info != NULL) { 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; +#if TIZEN_FEATURE_BT_OTP + param = g_variant_new("(ssb)", + notify_change.att_handle, + notify_change.service_handle, + notify_change.att_notify); + __bt_send_event_to_otp(BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED, param); +#endif _bt_common_event_cb( BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED, BLUETOOTH_ERROR_NONE, ¬ify_change, user_info->cb, user_info->user_data); } } + g_object_unref(invocation); + return; } else if (g_strcmp0(method_name, "StopNotify") == 0) { bt_user_info_t *user_info = NULL; bt_gatt_char_notify_change_t notify_change = {0, }; +#if TIZEN_FEATURE_BT_OTP + GVariant *param = NULL; +#endif BT_DBG("StopNotify"); user_info = _bt_get_user_data(BT_COMMON); if (user_info != NULL) { 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; +#if TIZEN_FEATURE_BT_OTP + param = g_variant_new("(ssb)", + notify_change.att_handle, + notify_change.service_handle, + notify_change.att_notify); + __bt_send_event_to_otp(BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED, param); +#endif _bt_common_event_cb( BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED, BLUETOOTH_ERROR_NONE, ¬ify_change, user_info->cb, user_info->user_data); } } + g_object_unref(invocation); + return; } else if (g_strcmp0(method_name, "IndicateConfirm") == 0) { 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"); @@ -790,25 +1075,26 @@ 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_INDICATE_CONFIRMED, + BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_COMPLETED, BLUETOOTH_ERROR_NONE, &confirm, user_info->cb, user_info->user_data); } } } + g_dbus_method_invocation_return_value(invocation, NULL); } @@ -821,69 +1107,63 @@ static void __bt_gatt_desc_method_call(GDBusConnection *connection, GDBusMethodInvocation *invocation, gpointer user_data) { - GVariantBuilder *inner_builder = NULL; - int i; - 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("Remote Device address number = %s", addr); - BT_DBG("Request id = %d, Offset = %d", req_id, offset); - BT_DBG("Sender = %s", sender); - read_req.att_handle = g_strdup(object_path); - read_req.address = g_strdup(addr); - read_req.req_id = req_id; - read_req.offset = 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; + } + 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); + if (svc_info == NULL) { + BT_ERR("Coudn't find service for %s", object_path); + g_dbus_method_invocation_return_value(invocation, NULL); + return; + } - /* 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); + g_variant_get(parameters, "(&suq)", &addr, &req_id, &offset); + BT_DBG("Request id = %u, Offset = %u", req_id, offset); - if (user_info != NULL) { - struct gatt_char_info *char_info = NULL; + read_req.att_handle = (char *)object_path; + read_req.address = addr; + read_req.req_id = req_id; + read_req.offset = offset; + read_req.service_handle = svc_info->serv_path; - _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; @@ -894,58 +1174,72 @@ 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); - if (!value_change.att_value) { - BT_ERR("att_value is NULL"); - g_variant_unref(var); - g_dbus_method_invocation_return_value(invocation, NULL); - return; - } + value_change.att_value = (guint8 *)g_malloc(len); + 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) @@ -955,13 +1249,13 @@ gboolean __bt_gatt_emit_interface_removed(gchar *object_path, gchar *interface) GVariantBuilder *array_builder; array_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); - g_variant_builder_init(array_builder, G_VARIANT_TYPE ("as")); + g_variant_builder_init(array_builder, G_VARIANT_TYPE("as")); g_variant_builder_add(array_builder, "s", interface); ret = g_dbus_connection_emit_signal(g_conn, NULL, "/", "org.freedesktop.Dbus.Objectmanager", "InterfacesRemoved", - g_variant_new ("(oas)", + g_variant_new("(oas)", object_path, array_builder), &error); @@ -982,20 +1276,29 @@ static const GDBusInterfaceVTable desc_interface_vtable = { __bt_gatt_desc_method_call, NULL, NULL, + { 0 } }; static const GDBusInterfaceVTable char_interface_vtable = { __bt_gatt_char_method_call, NULL, NULL, + { 0 } }; static const GDBusInterfaceVTable serv_interface_vtable = { - __bt_gatt_serv_method_call, NULL, NULL, + NULL, + { 0 } }; +static const GDBusInterfaceVTable manager_interface_vtable = { + __bt_gatt_manager_method_call, + NULL, + NULL, + { 0 } +}; static GDBusNodeInfo *__bt_gatt_create_method_node_info( const gchar *introspection_data) @@ -1006,12 +1309,16 @@ static GDBusNodeInfo *__bt_gatt_create_method_node_info( if (introspection_data == NULL) return NULL; + + BT_DBG("Create new node info"); node_info = g_dbus_node_info_new_for_xml(introspection_data, &err); if (err) { BT_ERR("Unable to create node: %s", err->message); g_clear_error(&err); + return NULL; } + return node_info; } @@ -1043,8 +1350,7 @@ static struct gatt_char_info *__bt_gatt_find_gatt_char_info( for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) { struct gatt_char_info *char_info = l2->data; - if (g_strcmp0(char_info->char_path, char_path) - == 0) + if (g_strcmp0(char_info->char_path, char_path) == 0) return char_info; } BT_ERR("Gatt characteristic not found"); @@ -1068,8 +1374,7 @@ static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info( for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) { struct gatt_char_info *char_info = l2->data; - if (g_strcmp0(char_info->char_path, char_path) - == 0) { + if (g_strcmp0(char_info->char_path, char_path) == 0) { for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) { struct gatt_desc_info *desc_info = l3->data; if (g_strcmp0(desc_info->desc_path, @@ -1092,92 +1397,27 @@ static struct gatt_req_info *__bt_gatt_find_request_info(guint request_id) for (l = gatt_requests; l != NULL; l = l->next) { struct gatt_req_info *req_info = l->data; - if (req_info && req_info->request_id == request_id) { + if (req_info && req_info->request_id == request_id) return req_info; - } } BT_ERR("Gatt Request not found"); return NULL; } -static int char_info_cmp(gconstpointer a1, gconstpointer a2) -{ - const struct gatt_char_info *attrib1 = a1; - const struct gatt_char_info *attrib2 = a2; - - return g_strcmp0(attrib1->char_path, attrib2->char_path); -} - -static int desc_info_cmp(gconstpointer a1, gconstpointer a2) -{ - const struct gatt_desc_info *attrib1 = a1; - const struct gatt_desc_info *attrib2 = a2; - - return g_strcmp0(attrib1->desc_path, attrib2->desc_path); -} - -static gboolean __bt_gatt_update_attribute_info(struct gatt_req_info *req_info, - char *value, int value_length) -{ - GSList *l1, *l2, *l3; - int found = 0; - for (l1 = gatt_services; l1 != NULL; l1 = l1->next) { - struct gatt_service_info *serv_info = l1->data; - - if (serv_info && g_strcmp0(serv_info->serv_path, req_info->svc_path) == 0) { - - for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) { - struct gatt_char_info *char_info = l2->data; - - if (char_info) { - if (g_strcmp0(char_info->char_path, req_info->attr_path) == 0) { - memcpy(&char_info->char_value[req_info->offset], value, value_length); - serv_info->char_data = g_slist_insert_sorted (serv_info->char_data, char_info, char_info_cmp); - found = 1; - break; - } else { - for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) { - struct gatt_desc_info *desc_info = l3->data; - - if (desc_info && g_strcmp0(desc_info->desc_path, req_info->attr_path) - == 0) { - memcpy(&desc_info->desc_value[req_info->offset], value, value_length); - char_info->desc_data = g_slist_insert_sorted (char_info->desc_data, desc_info, desc_info_cmp); - found = 1; - break; - } - } - } - } - } - } - if (found) { - return TRUE;; - } - } - return FALSE; -} - static GDBusProxy *__bt_gatt_gdbus_init_manager_proxy(const gchar *service, const gchar *path, const gchar *interface) { GDBusProxy *proxy; GError *err = NULL; - if (g_conn == NULL) - g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, - NULL, &err); - + g_conn = _bt_get_system_shared_conn(); if (!g_conn) { - if (err) { - BT_ERR("Unable to connect to gdbus: %s", err->message); - g_clear_error(&err); - } + BT_ERR("Unable to get connection"); return NULL; } proxy = g_dbus_proxy_new_sync(g_conn, - G_DBUS_PROXY_FLAGS_NONE, NULL, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, service, path, interface, NULL, &err); @@ -1201,67 +1441,9 @@ static GDBusProxy *__bt_gatt_gdbus_get_manager_proxy(const gchar *service, path, interface); } -int bluetooth_gatt_convert_prop2string( - bt_gatt_characteristic_property_t properties, - char *char_properties[]) +static gboolean __bt_gatt_is_service_registered(const char *service_path) { - int flag_count = 0; - - if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST) { - char_properties[flag_count] = g_strdup("broadcast"); - flag_count++; - } - if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ) { - char_properties[flag_count] = g_strdup("read"); - flag_count++; - } - if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE) { - char_properties[flag_count] = g_strdup("write-without-response"); - flag_count++; - } - if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE) { - char_properties[flag_count] = g_strdup("write"); - flag_count++; - } - if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) { - char_properties[flag_count] = g_strdup("notify"); - flag_count++; - } - if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE) { - char_properties[flag_count] = g_strdup("indicate"); - flag_count++; - } - if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE) { - char_properties[flag_count] = g_strdup("authenticated-signed-writes"); - flag_count++; - } - - if (flag_count == 0) { - char_properties[flag_count] = g_strdup("read"); - flag_count++; - } - - return flag_count; -} - -static void __bt_gatt_set_service_state(const char *service_path, - gboolean state) -{ - struct gatt_service_info *svc_info = NULL; - svc_info = __bt_gatt_find_gatt_service_info(service_path); - - if (svc_info != NULL) { - BT_DBG("Updating the gatt service register state %d", state); - svc_info->is_svc_registered = state; - return; - } - - BT_DBG("gatt service not found"); -} - -static gboolean __bt_gatt_get_service_state(const char *service_path) -{ - struct gatt_service_info *svc_info = NULL; + struct gatt_service_info *svc_info = NULL; svc_info = __bt_gatt_find_gatt_service_info(service_path); @@ -1288,21 +1470,18 @@ void get_service_cb(GObject *object, GAsyncResult *res, gpointer user_data) int n_char = 1; BT_DBG(" "); - result = g_dbus_proxy_call_finish(manager_gproxy, res, &error); + result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if (result == NULL) { - /* dBUS-RPC is failed */ - BT_ERR("Dbus-RPC is failed\n"); - + BT_ERR("Dbus-RPC is failed"); if (error != NULL) { - /* dBUS gives error cause */ - BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n", - error->code, error->message); + BT_ERR("D-Bus API failure: errCode[%x], message[%s]", + error->code, error->message); g_clear_error(&error); } } else { char *char_cmp = NULL; - g_variant_get (result, "(a{sv})", &iter); + g_variant_get(result, "(a{sv})", &iter); char_cmp = g_strdup_printf("Characteristic%d", n_char); while (g_variant_iter_loop(iter, "{sv}", &key, &value)) { @@ -1319,6 +1498,8 @@ void get_service_cb(GObject *object, GAsyncResult *res, gpointer user_data) BT_DBG("Descriptor %s", descriptor); } } + g_variant_iter_free(iter); + /* TODO: Store the service informationa and * Send respponse to CAPI layer. */ @@ -1327,153 +1508,196 @@ void get_service_cb(GObject *object, GAsyncResult *res, gpointer user_data) g_free(char_cmp); } } -void register_service_cb(GObject *object, GAsyncResult *res, gpointer user_data) +void register_application_cb(GObject *object, GAsyncResult *res, gpointer user_data) { - BT_DBG("register_service_cb\n"); + BT_INFO("RegisterApplication is completed"); GError *error = NULL; GVariant *result; - register_pending_cnt = 0; - - result = g_dbus_proxy_call_finish(manager_gproxy, res, &error); - - if (result == NULL) { - /* dBUS-RPC is failed */ - BT_ERR("Dbus-RPC is failed\n"); - - if (error != NULL) { - /* dBUS gives error cause */ - BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n", - error->code, error->message); - g_clear_error(&error); - } + if (register_cancel) { + g_object_unref(register_cancel); + register_cancel = NULL; } -} - -void unregister_service_cb(GObject *object, GAsyncResult *res, - gpointer user_data) -{ - BT_DBG("unregister_service_cb\n"); - - GError *error = NULL; - GVariant *result; - - result = g_dbus_proxy_call_finish(manager_gproxy, res, &error); + result = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); if (result == NULL) { - /* dBUS-RPC is failed */ - BT_ERR("Dbus-RPC is failed\n"); - + BT_ERR("Dbus-RPC is failed"); if (error != NULL) { - /* dBUS gives error cause */ - BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n", + BT_ERR("D-Bus API failure: errCode[%x], message[%s]", error->code, error->message); g_clear_error(&error); } + is_server_started = false; + } else { + g_variant_unref(result); } } -static int __bt_gatt_unregister_service(const char *service_path) +BT_EXPORT_API int bluetooth_gatt_unregister_application(void) { - if (!__bt_gatt_get_service_state(service_path)) { - BT_DBG("service not registered \n"); - return BLUETOOTH_ERROR_NOT_FOUND; - } - GDBusProxy *proxy = NULL; - proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez", - "/org/bluez/hci0", GATT_MNGR_INTERFACE); - - if (proxy == NULL) - return BLUETOOTH_ERROR_INTERNAL; - - /* Async Call to Unregister Service */ - g_dbus_proxy_call(proxy, - "UnregisterService", - g_variant_new("(o)", - service_path), - G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - (GAsyncReadyCallback) unregister_service_cb, - NULL); - - __bt_gatt_set_service_state(service_path, FALSE); + if (is_server_started) { + GVariant *ret; + GError *err = NULL; - return BLUETOOTH_ERROR_NONE; -} + if (app_path == NULL) { + BT_ERR("app_path is NULL"); + return BLUETOOTH_ERROR_INTERNAL; + } -static GDBusConnection *__bt_gatt_get_gdbus_connection(void) -{ - GDBusConnection *local_system_gconn = NULL; - GError *err = NULL; + proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez", + "/org/bluez/hci0", GATT_MNGR_INTERFACE); + if (proxy == NULL) { + BT_ERR("proxy is NULL"); + return BLUETOOTH_ERROR_INTERNAL; + } - if (g_conn == NULL) { - g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); - if (!g_conn) { - if (err) { - BT_ERR("Unable to connect to dbus: %s", err->message); + BT_INFO("UnregisterApplication"); + + /* Async Call to Unregister Service */ + ret = g_dbus_proxy_call_sync(proxy, "UnregisterApplication", + g_variant_new("(o)", app_path), G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &err); + if (ret == NULL) { + BT_ERR("dBUS-RPC is failed"); + if (err != NULL) { + BT_ERR("D-Bus API failure: errCode[%x], message[%s]", + err->code, err->message); + if (err->code == G_DBUS_ERROR_SERVICE_UNKNOWN || + g_strrstr(err->message, BT_ERROR_DOES_NOT_EXIST)) { + g_clear_error(&err); + goto done; + } g_clear_error(&err); } - g_conn = NULL; + return BLUETOOTH_ERROR_INTERNAL; } - } else if (g_dbus_connection_is_closed(g_conn)) { - local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + g_variant_unref(ret); - if (!local_system_gconn) { - BT_ERR("Unable to connect to dbus: %s", err->message); - g_clear_error(&err); - } +done: + is_server_started = false; + + BT_INFO("UnregisterApplication is completed"); - g_conn = local_system_gconn; + return BLUETOOTH_ERROR_NONE; } - return g_conn; + BT_INFO("GATT server not started"); + return BLUETOOTH_ERROR_NONE; } BT_EXPORT_API int bluetooth_gatt_init(void) { - GDBusConnection *conn; + GError *error = NULL; + GDBusNodeInfo *node_info = NULL; + + if (app_path != NULL) { + BT_ERR("app path already exists! initialized"); + return BLUETOOTH_ERROR_ALREADY_INITIALIZED; + } + + g_conn = _bt_get_system_shared_conn(); + if (!g_conn) { + BT_ERR("Unable to get connection"); + goto failed; + } - owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, - BT_GATT_SERVICE_NAME, - G_BUS_NAME_OWNER_FLAGS_NONE, - NULL, NULL, NULL, NULL, NULL); + if (owner_id == 0) { + gchar *name = g_strdup_printf("%s.p%d", BT_GATT_SERVICE_NAME, getpid()); + BT_DBG("well-known name: %s", name); + owner_id = g_bus_own_name_on_connection(g_conn, name, + G_BUS_NAME_OWNER_FLAGS_NONE, + NULL, NULL, NULL, NULL); + g_free(name); + } BT_DBG("owner_id is [%d]", owner_id); + app_path = g_strdup_printf("/com/%d", getpid()); + serv_id = 1; - conn = __bt_gatt_get_gdbus_connection(); - if (!conn) { - BT_ERR("Unable to get connection"); - return BLUETOOTH_ERROR_INTERNAL; + /* Register ObjectManager interface */ + node_info = __bt_gatt_create_method_node_info( + manager_introspection_xml); + if (node_info == NULL) { + BT_ERR("failed to get node info"); + goto failed; + } + + if (manager_id == 0) { + BT_INFO("manager_id does not exists"); + + manager_id = g_dbus_connection_register_object(g_conn, app_path, + node_info->interfaces[0], + &manager_interface_vtable, + NULL, NULL, &error); + } + g_dbus_node_info_unref(node_info); + if (manager_id == 0) { + BT_ERR("failed to register: %s", error->message); + g_error_free(error); + goto failed; } return BLUETOOTH_ERROR_NONE; + +failed: + if (owner_id) + g_bus_unown_name(owner_id); + + g_free(app_path); + + app_path = NULL; + owner_id = 0; + + return BLUETOOTH_ERROR_INTERNAL; } BT_EXPORT_API int bluetooth_gatt_deinit() { - /* Unown gdbus bus */ - if (owner_id) { + int ret = BLUETOOTH_ERROR_NONE; + + if (register_cancel) { + g_cancellable_cancel(register_cancel); + g_object_unref(register_cancel); + register_cancel = NULL; + } - /* remove/unregister all services */ - BT_DBG("removing all registered gatt service\n"); - bluetooth_gatt_delete_services(); + if (owner_id == 0) { + BT_ERR("owner_id is zero"); + return BLUETOOTH_ERROR_NOT_FOUND; + } - g_bus_unown_name(owner_id); + BT_DBG("Removing all registered gatt services"); + bluetooth_gatt_delete_services(); - BT_DBG("Gatt service deinitialized \n"); + /* Unregister the exported interface for object manager */ + if (manager_id) { + g_dbus_connection_unregister_object(g_conn, manager_id); + manager_id = 0; + } + + ret = bluetooth_gatt_unregister_application(); + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Fail to unregister application"); + } - g_slist_free(gatt_services); - gatt_services = NULL; + g_bus_unown_name(owner_id); + owner_id = 0; - return BLUETOOTH_ERROR_NONE; + g_free(app_path); + app_path = NULL; + + if (manager_gproxy) { + g_object_unref(manager_gproxy); + manager_gproxy = NULL; } - return BLUETOOTH_ERROR_NOT_FOUND; + BT_DBG("-"); + return ret; } BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid, @@ -1491,17 +1715,17 @@ BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid, node_info = __bt_gatt_create_method_node_info( service_introspection_xml); - if (node_info == NULL) return BLUETOOTH_ERROR_INTERNAL; - path = g_strdup_printf(GATT_SERV_OBJECT_PATH"%d", serv_id++); + path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, serv_id++); BT_DBG("gatt service path is [%s]", path); object_id = g_dbus_connection_register_object(g_conn, path, node_info->interfaces[0], &serv_interface_vtable, NULL, NULL, &error); + g_dbus_node_info_unref(node_info); if (object_id == 0) { BT_ERR("failed to register: %s", error->message); @@ -1548,6 +1772,12 @@ BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid, g_variant_new("(oa{sa{sv}})", path, builder), &error); + if (error != NULL) { + /* dbus gives error cause */ + BT_ERR("d-bus api failure: errcode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + } new_service = TRUE; @@ -1563,6 +1793,7 @@ BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid, BT_EXPORT_API int bluetooth_gatt_add_new_characteristic( const char *svc_path, const char *char_uuid, + bt_gatt_permission_t permissions, bt_gatt_characteristic_property_t properties, char **char_path) { @@ -1594,7 +1825,6 @@ BT_EXPORT_API int bluetooth_gatt_add_new_characteristic( node_info = __bt_gatt_create_method_node_info( characteristics_introspection_xml); - if (node_info == NULL) return BLUETOOTH_ERROR_INTERNAL; @@ -1605,6 +1835,7 @@ BT_EXPORT_API int bluetooth_gatt_add_new_characteristic( node_info->interfaces[0], &char_interface_vtable, NULL, NULL, &error); + g_dbus_node_info_unref(node_info); if (object_id == 0) { BT_ERR("failed to register: %s", error->message); @@ -1614,6 +1845,15 @@ BT_EXPORT_API int bluetooth_gatt_add_new_characteristic( return BLUETOOTH_ERROR_INTERNAL; } + if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_READ) + properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ; + if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ) + properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ; + if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_WRITE) + properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE; + if (permissions & BLUETOOTH_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE) + properties |= BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE; + flag_count = bluetooth_gatt_convert_prop2string(properties, char_flags); char_info = g_new0(struct gatt_char_info, 1); @@ -1622,9 +1862,9 @@ BT_EXPORT_API int bluetooth_gatt_add_new_characteristic( char_info->char_id = object_id; char_info->char_uuid = g_strdup(char_uuid); - for (i = 0; i < flag_count; i++) { + for (i = 0; i < flag_count; i++) char_info->char_flags[i] = char_flags[i]; - } + char_info->flags_length = flag_count; @@ -1640,9 +1880,8 @@ BT_EXPORT_API int bluetooth_gatt_add_new_characteristic( builder2 = g_variant_builder_new(G_VARIANT_TYPE("as")); - for (i = 0; i < flag_count; i++) { + for (i = 0; i < flag_count; i++) g_variant_builder_add(builder2, "s", char_flags[i]); - } flags_val = g_variant_new("as", builder2); g_variant_builder_add(inner_builder, "{sv}", "Flags", @@ -1663,6 +1902,12 @@ BT_EXPORT_API int bluetooth_gatt_add_new_characteristic( g_variant_new("(oa{sa{sv}})", path, builder), &error); + if (error) { + /* dBUS gives error cause */ + BT_ERR("Could not Emit Signal: errCode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + } *char_path = g_strdup(path); @@ -1694,7 +1939,7 @@ BT_EXPORT_API int bluetooth_gatt_set_characteristic_value( int res = BLUETOOTH_ERROR_NONE; line_argv = g_strsplit_set(characteristic, "/", 0); - serv_path = g_strdup_printf("/%s", line_argv[1]); + serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]); char_info = __bt_gatt_find_gatt_char_info(serv_path, characteristic); @@ -1721,12 +1966,11 @@ BT_EXPORT_API int bluetooth_gatt_set_characteristic_value( builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); - for (i = 0; i < value_length; i++) { + for (i = 0; i < value_length; i++) g_variant_builder_add(builder1, "y", char_value[i]); - } char_val = g_variant_new("ay", builder1); - g_variant_builder_add(inner_builder, "{sv}", "Value", char_val); + g_variant_builder_add(inner_builder, "{sv}", "Value", char_val); g_variant_builder_add(builder, "{sa{sv}}", GATT_CHAR_INTERFACE, @@ -1736,9 +1980,15 @@ BT_EXPORT_API int bluetooth_gatt_set_characteristic_value( "org.freedesktop.Dbus.ObjectManager", "InterfacesAdded", g_variant_new("(oa{sa{sv}})", - char_info->char_path, builder), + char_info->char_path, builder), &error); + if (error) { + /* dBUS gives error cause */ + BT_ERR("Could not Emit Signal: errCode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + } g_variant_builder_unref(inner_builder); g_variant_builder_unref(builder); g_variant_builder_unref(builder1); @@ -1751,6 +2001,7 @@ done: BT_EXPORT_API int bluetooth_gatt_add_descriptor( const char *char_path, const char *desc_uuid, + bt_gatt_permission_t permissions, char **desc_path) { static int desc_id = 1; @@ -1764,6 +2015,11 @@ BT_EXPORT_API int bluetooth_gatt_add_descriptor( struct gatt_desc_info *desc_info = NULL; gchar **line_argv = NULL; char *serv_path; + GVariantBuilder *builder2 = NULL; + GVariant *flags_val = NULL; + int i = 0; + char *desc_flags[NUMBER_OF_FLAGS]; + int flag_count = 0; if (new_char) { desc_id = 1; @@ -1771,19 +2027,20 @@ BT_EXPORT_API int bluetooth_gatt_add_descriptor( } line_argv = g_strsplit_set(char_path, "/", 0); - serv_path = g_strdup_printf("/%s", line_argv[1]); + serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]); char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path); if (char_info == NULL) { g_strfreev(line_argv); + g_free(serv_path); return BLUETOOTH_ERROR_INVALID_PARAM; } node_info = __bt_gatt_create_method_node_info( descriptor_introspection_xml); - if (node_info == NULL) { g_strfreev(line_argv); + g_free(serv_path); return BLUETOOTH_ERROR_INTERNAL; } @@ -1794,22 +2051,31 @@ BT_EXPORT_API int bluetooth_gatt_add_descriptor( node_info->interfaces[0], &desc_interface_vtable, NULL, NULL, &error); + g_dbus_node_info_unref(node_info); if (object_id == 0) { BT_ERR("failed to register: %s", error->message); g_error_free(error); g_free(path); g_strfreev(line_argv); + g_free(serv_path); return BLUETOOTH_ERROR_INTERNAL; } + flag_count = bluetooth_gatt_convert_perm2string(permissions, desc_flags); + desc_info = g_new0(struct gatt_desc_info, 1); desc_info->desc_path = g_strdup(path); desc_info->desc_id = object_id; desc_info->desc_uuid = g_strdup(desc_uuid); + for (i = 0; i < flag_count; i++) + desc_info->desc_flags[i] = desc_flags[i]; + + desc_info->flags_length = flag_count; + char_info->desc_data = g_slist_append(char_info->desc_data, desc_info); builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}")); @@ -1820,6 +2086,15 @@ BT_EXPORT_API int bluetooth_gatt_add_descriptor( g_variant_builder_add(inner_builder, "{sv}", "Characteristic", g_variant_new("o", char_path)); + builder2 = g_variant_builder_new(G_VARIANT_TYPE("as")); + + for (i = 0; i < flag_count; i++) + g_variant_builder_add(builder2, "s", desc_flags[i]); + + flags_val = g_variant_new("as", builder2); + g_variant_builder_add(inner_builder, "{sv}", "Flags", + flags_val); + g_variant_builder_add(builder, "{sa{sv}}", GATT_DESC_INTERFACE, inner_builder); @@ -1830,13 +2105,21 @@ BT_EXPORT_API int bluetooth_gatt_add_descriptor( g_variant_new("(oa{sa{sv}})", path, builder), &error); + if (error) { + /* dBUS gives error cause */ + BT_ERR("Could not Emit Signal: errCode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + } *desc_path = g_strdup(path); g_free(path); + g_free(serv_path); g_strfreev(line_argv); g_variant_builder_unref(inner_builder); g_variant_builder_unref(builder); + g_variant_builder_unref(builder2); return BLUETOOTH_ERROR_NONE; } @@ -1857,8 +2140,8 @@ BT_EXPORT_API int bluetooth_gatt_set_descriptor_value( int i ; line_argv = g_strsplit_set(desc_path, "/", 0); - serv_path = g_strdup_printf("/%s", line_argv[1]); - char_path = g_strdup_printf("%s/%s", serv_path, line_argv[2]); + serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]); + char_path = g_strdup_printf("%s/%s", serv_path, line_argv[4]); desc_info = __bt_gatt_find_gatt_desc_info(serv_path, char_path, desc_path); @@ -1885,9 +2168,9 @@ BT_EXPORT_API int bluetooth_gatt_set_descriptor_value( builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); - for (i = 0; i < value_length; i++) { + for (i = 0; i < value_length; i++) g_variant_builder_add(builder1, "y", desc_value[i]); - } + desc_val = g_variant_new("ay", builder1); g_variant_builder_add(inner_builder, "{sv}", "Value", desc_val); @@ -1899,9 +2182,16 @@ BT_EXPORT_API int bluetooth_gatt_set_descriptor_value( "org.freedesktop.Dbus.ObjectManager", "InterfacesAdded", g_variant_new("(oa{sa{sv}})", - desc_info->desc_path, builder), + desc_info->desc_path, builder), &error); + if (error != NULL) { + BT_ERR("D-Bus API failure: errCode[%x], \ + message[%s]", + error->code, error->message); + g_clear_error(&error); + } + g_variant_builder_unref(inner_builder); g_variant_builder_unref(builder); g_variant_builder_unref(builder1); @@ -1935,38 +2225,73 @@ int bluetooth_gatt_get_service(const char *svc_uuid) return BLUETOOTH_ERROR_NONE; } -BT_EXPORT_API int bluetooth_gatt_register_service( - const char *svc_path) +BT_EXPORT_API int bluetooth_gatt_register_service(const char *svc_path) { - GDBusProxy *proxy = NULL; - gchar *path = NULL; - - register_pending_cnt++; + struct gatt_service_info *svc_info = NULL; - if (__bt_gatt_get_service_state(svc_path)) { - BT_DBG("service already registered \n"); - return BLUETOOTH_ERROR_NONE; + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_GATT_REGISTER_SERVICE) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have aprivilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; } - proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez", - "/org/bluez/hci0", GATT_MNGR_INTERFACE); - if (proxy == NULL) + svc_info = __bt_gatt_find_gatt_service_info(svc_path); + if (svc_info == NULL) { + BT_ERR("Cannot find service [%s]", svc_path); return BLUETOOTH_ERROR_INTERNAL; + } + svc_info->is_svc_registered = TRUE; - path = g_strdup(svc_path); + return BLUETOOTH_ERROR_NONE; +} - g_dbus_proxy_call(proxy, - "RegisterService", - g_variant_new("(oa{sv})", - path, NULL), - G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - (GAsyncReadyCallback) register_service_cb, - NULL); +BT_EXPORT_API int bluetooth_gatt_register_application(void) +{ + GDBusProxy *proxy = NULL; - __bt_gatt_set_service_state(svc_path, TRUE); + if (!is_server_started) { + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_GATT_REGISTER_APPLICATION) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have aprivilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; + } - g_free(path); + if (g_slist_length(gatt_services) == 0) { + BT_ERR("There is no registered service"); + return BLUETOOTH_ERROR_INTERNAL; + } + + if (app_path == NULL) { + BT_ERR("app_path is NULL"); + return BLUETOOTH_ERROR_INTERNAL; + } + + proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez", + "/org/bluez/hci0", GATT_MNGR_INTERFACE); + if (proxy == NULL) { + BT_ERR("proxy is NULL"); + return BLUETOOTH_ERROR_INTERNAL; + } + + BT_INFO("RegisterApplication"); + + if (register_cancel) { + g_cancellable_cancel(register_cancel); + g_object_unref(register_cancel); + } + register_cancel = g_cancellable_new(); + + g_dbus_proxy_call(proxy, "RegisterApplication", + g_variant_new("(oa{sv})", app_path, NULL), + G_DBUS_CALL_FLAGS_NONE, -1, register_cancel, + (GAsyncReadyCallback)register_application_cb, NULL); + + is_server_started = true; + + return BLUETOOTH_ERROR_NONE; + } + + BT_INFO("Already RegisterApplication"); return BLUETOOTH_ERROR_NONE; } @@ -1974,34 +2299,31 @@ BT_EXPORT_API int bluetooth_gatt_register_service( BT_EXPORT_API int bluetooth_gatt_delete_services(void) { GSList *l; - int error = BLUETOOTH_ERROR_NONE; - l = gatt_services; - - if (l != NULL) { - for (l = gatt_services; l != NULL; l = l->next) { - struct gatt_service_info *info = l->data; - BT_DBG("svc_path is %s", info->serv_path); - if (bluetooth_gatt_unregister_service(info->serv_path) - != BLUETOOTH_ERROR_NONE) { - error = BLUETOOTH_ERROR_INTERNAL; - BT_DBG(" Error in removing service %s \n", - info->serv_path); - } - } - BT_DBG(" All services removed successfully.\n "); + int ret = BLUETOOTH_ERROR_NONE; + + if (gatt_services == NULL) { + BT_DBG("There are no registered services"); + serv_id = 1; + return ret; } - else { - BT_DBG(" There are no registered services.\n "); + + for (l = gatt_services; l != NULL; ) { + struct gatt_service_info *info = l->data; + + // In __bt_gatt_unregister_service, current node will be removed. + // Go forward to next node before calling __bt_gatt_unregister_service. + l = l->next; + if (__bt_gatt_unregister_service(info) != BLUETOOTH_ERROR_NONE) { + ret = BLUETOOTH_ERROR_INTERNAL; + } } + BT_INFO("All services are removed : %d", ret); g_slist_free(gatt_services); gatt_services = NULL; serv_id = 1; - if (error != BLUETOOTH_ERROR_NONE) - return error; - - return BLUETOOTH_ERROR_NONE; + return ret; } BT_EXPORT_API int bluetooth_gatt_update_characteristic( @@ -2018,12 +2340,14 @@ BT_EXPORT_API int bluetooth_gatt_update_characteristic( int i = 0; gchar **line_argv = NULL; gchar *serv_path = NULL; + const char *value = NULL; line_argv = g_strsplit_set(char_path, "/", 0); - serv_path = g_strdup_printf("/%s", line_argv[1]); + serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]); - if (!__bt_gatt_get_service_state(serv_path)) { - BT_DBG("service not registered for this characteristic \n"); + if (!__bt_gatt_is_service_registered(serv_path)) { + BT_DBG("service not registered for this characteristic"); + g_free(serv_path); g_strfreev(line_argv); return BLUETOOTH_ERROR_INTERNAL; } @@ -2032,17 +2356,15 @@ BT_EXPORT_API int bluetooth_gatt_update_characteristic( invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); inner_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); - for (i = 0; i < value_length; i++) { + for (i = 0; i < value_length; i++) g_variant_builder_add(inner_builder, "y", char_value[i]); - } update_value = g_variant_new("ay", inner_builder); - outer_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); g_variant_builder_add(outer_builder, "{sv}", "Value", update_value); - BT_DBG("Updating characteristic value \n"); + BT_DBG("Updating characteristic value"); ret = g_dbus_connection_emit_signal(g_conn, NULL, char_path, "org.freedesktop.DBus.Properties", @@ -2065,19 +2387,36 @@ BT_EXPORT_API int bluetooth_gatt_update_characteristic( char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path); if (char_info == NULL) { + g_free(serv_path); + g_strfreev(line_argv); + g_variant_builder_unref(inner_builder); + g_variant_builder_unref(outer_builder); + g_variant_builder_unref(invalidated_builder); + return BLUETOOTH_ERROR_INVALID_DATA; } char_info->value_length = value_length; - char_info->char_value = (char *)realloc(char_info->char_value, value_length); + value = (char *)realloc(char_info->char_value, value_length); + if (value == NULL) { + g_free(serv_path); + g_strfreev(line_argv); + g_variant_builder_unref(inner_builder); + g_variant_builder_unref(outer_builder); + g_variant_builder_unref(invalidated_builder); + + return BLUETOOTH_ERROR_MEMORY_ALLOCATION; + } + + char_info->char_value = (char*)value; if (char_info->char_value) { - for (i = 0; i < value_length; i++) { + for (i = 0; i < value_length; i++) char_info->char_value[i] = char_value[i]; - } } } + g_free(serv_path); g_strfreev(line_argv); g_variant_builder_unref(inner_builder); g_variant_builder_unref(outer_builder); @@ -2086,80 +2425,147 @@ BT_EXPORT_API int bluetooth_gatt_update_characteristic( return err; } -BT_EXPORT_API int bluetooth_gatt_unregister_service(const char *svc_path) +static void __bt_gatt_free_descriptor_info(struct gatt_desc_info *desc_info) { - GSList *l, *l1; - struct gatt_service_info *svc_info; - gboolean ret; - int err = BLUETOOTH_ERROR_NONE; - GSList *tmp; + int i; - BT_DBG("svc_path %s", svc_path); - svc_info = __bt_gatt_find_gatt_service_info(svc_path); + if (!desc_info) + return; - if (!svc_info) { - BT_ERR("Unable to find service info"); - return BLUETOOTH_ERROR_NOT_FOUND; - } + g_free(desc_info->desc_path); + g_free(desc_info->desc_uuid); + g_free(desc_info->desc_value); - err = __bt_gatt_unregister_service(svc_path); - if (err != BLUETOOTH_ERROR_NONE) { - BT_DBG("Could not unregister application"); - return err; - } + for (i = 0; i < desc_info->flags_length; i++) + g_free(desc_info->desc_flags[i]); - for (l = svc_info->char_data; l != NULL; l = l->next) { - struct gatt_char_info *char_info = l->data; + g_free(desc_info); +} - for (l1 = char_info->desc_data; l1 != NULL; l1 = l1->next) { - struct gatt_desc_info *desc_info = l1->data; +static void __bt_gatt_free_characteristic_info(struct gatt_char_info *char_info) +{ + int i; - ret = g_dbus_connection_unregister_object(g_conn, - desc_info->desc_id); - if (ret) { - __bt_gatt_emit_interface_removed( - desc_info->desc_path, - GATT_DESC_INTERFACE); - } else { - err = BLUETOOTH_ERROR_INTERNAL; - } - } - ret = g_dbus_connection_unregister_object(g_conn, - char_info->char_id); - if (ret) { - __bt_gatt_emit_interface_removed(char_info->char_path, - GATT_CHAR_INTERFACE); - } else { - err = BLUETOOTH_ERROR_INTERNAL; - } - } - ret = g_dbus_connection_unregister_object(g_conn, svc_info->serv_id); - if (ret) { - __bt_gatt_emit_interface_removed(svc_info->serv_path, - GATT_SERV_INTERFACE); - } else { - err = BLUETOOTH_ERROR_INTERNAL; - } + if (!char_info) + return; - ret = g_dbus_connection_unregister_object(g_conn, svc_info->prop_id); - if (ret) { - BT_DBG("Unregistered the service on properties interface"); - } + g_free(char_info->char_path); + g_free(char_info->char_uuid); + g_free(char_info->char_value); - for (tmp = gatt_services; tmp != NULL; tmp = tmp->next) { - struct gatt_service_info *info = tmp->data; + for (i = 0; i < char_info->flags_length; i++) + g_free(char_info->char_flags[i]); - if (g_strcmp0(info->serv_path, svc_path) == 0) { - gatt_services = g_slist_delete_link(gatt_services, tmp->data); - } - } + g_free(char_info); +} - new_service = FALSE; +static void __bt_gatt_free_service_info(struct gatt_service_info *svc_info) +{ + if (!svc_info) + return; - if (gatt_services->next == NULL) - serv_id--; + g_free(svc_info->serv_path); + g_free(svc_info->service_uuid); + g_free(svc_info); +} - return err; +static void __desc_info_free(gpointer data, gpointer user_data) +{ + struct gatt_desc_info *desc_info = data; + int *err = user_data; + int ret; + + if (desc_info == NULL) + return; + + ret = g_dbus_connection_unregister_object(g_conn, desc_info->desc_id); + if (ret) { + __bt_gatt_emit_interface_removed(desc_info->desc_path, GATT_DESC_INTERFACE); + } else { + *err = BLUETOOTH_ERROR_INTERNAL; + } + __bt_gatt_free_descriptor_info(desc_info); +} + +static void __char_info_free(gpointer data, gpointer user_data) +{ + struct gatt_char_info *char_info = data; + int *err = user_data; + int ret; + + if (char_info == NULL) + return; + + g_slist_foreach(char_info->desc_data, __desc_info_free, user_data); + g_slist_free(char_info->desc_data); + char_info->desc_data = NULL; + + ret = g_dbus_connection_unregister_object(g_conn, char_info->char_id); + if (ret) { + __bt_gatt_emit_interface_removed(char_info->char_path, GATT_CHAR_INTERFACE); + } else { + *err = BLUETOOTH_ERROR_INTERNAL; + } + __bt_gatt_free_characteristic_info(char_info); +} + +static int __bt_gatt_unregister_service(struct gatt_service_info *svc_info) +{ + int ret = BLUETOOTH_ERROR_NONE; + + if (svc_info == NULL) { + BT_ERR("svc_info is NULL"); + return BLUETOOTH_ERROR_NOT_FOUND; + } + + if (svc_info->is_svc_registered == FALSE) { + BT_ERR("%s is not registered", svc_info->serv_path); + return BLUETOOTH_ERROR_NOT_FOUND; + } + + BT_DBG("svc_path %s", svc_info->serv_path); + + g_slist_foreach(svc_info->char_data, __char_info_free, &ret); + g_slist_free(svc_info->char_data); + svc_info->char_data = NULL; + + if (g_dbus_connection_unregister_object(g_conn, svc_info->serv_id) == FALSE) { + BT_ERR("Cannot unregister object for [%s]", svc_info->serv_path); + ret = BLUETOOTH_ERROR_INTERNAL; + } else { + __bt_gatt_emit_interface_removed(svc_info->serv_path, GATT_SERV_INTERFACE); + } + + gatt_services = g_slist_remove(gatt_services, svc_info); + __bt_gatt_free_service_info(svc_info); + + new_service = FALSE; + + if (gatt_services == NULL) { + serv_id = 1; + } else if (gatt_services->next == NULL) { + serv_id--; + } + + return ret; +} + +BT_EXPORT_API int bluetooth_gatt_unregister_service(const char *svc_path) +{ + struct gatt_service_info *svc_info; + int ret = BLUETOOTH_ERROR_NONE; + + BT_DBG("+"); + + svc_info = __bt_gatt_find_gatt_service_info(svc_path); + + ret = __bt_gatt_unregister_service(svc_info); + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Could not unregister service [%s]", svc_path); + } + + BT_DBG("-"); + return ret; } BT_EXPORT_API int bluetooth_gatt_send_response(int request_id, guint req_type, @@ -2167,41 +2573,25 @@ BT_EXPORT_API int bluetooth_gatt_send_response(int request_id, guint req_type, { struct gatt_req_info *req_info = NULL; - req_info = __bt_gatt_find_request_info(request_id); - - if (req_info) { - if (resp_state != BLUETOOTH_ERROR_NONE) { - - GQuark quark = g_quark_from_string("gatt-server"); - GError *err = g_error_new(quark, 0, "Application Error"); - g_dbus_method_invocation_return_gerror(req_info->context, err); - g_error_free(err); + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_GATT_SEND_RESPONSE) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have aprivilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; + } - gatt_requests = g_slist_remove(gatt_requests, req_info); + 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; + } - 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); + if (resp_state != BLUETOOTH_ATT_ERROR_NONE) { + BT_ERR("resp_state is 0x%X", resp_state); + char err_msg[20] = { 0, }; + g_snprintf(err_msg, sizeof(err_msg), "ATT error: 0x%02x", resp_state); + g_dbus_method_invocation_return_dbus_error(req_info->context, + "org.bluez.Error.Failed", err_msg); - 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; @@ -2210,9 +2600,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; } @@ -2231,14 +2644,17 @@ BT_EXPORT_API int bluetooth_gatt_server_set_notification(const char *char_path, char addr[20] = { 0 }; line_argv = g_strsplit_set(char_path, "/", 0); - serv_path = g_strdup_printf("/%s", line_argv[1]); + serv_path = g_strdup_printf("/%s/%s/%s", line_argv[1], line_argv[2], line_argv[3]); - if (!__bt_gatt_get_service_state(serv_path)) { - BT_DBG("service not registered for this characteristic \n"); + if (!__bt_gatt_is_service_registered(serv_path)) { + BT_DBG("service not registered for this characteristic"); + g_free(serv_path); g_strfreev(line_argv); return BLUETOOTH_ERROR_INTERNAL; } + g_free(serv_path); + outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); @@ -2252,7 +2668,7 @@ BT_EXPORT_API int bluetooth_gatt_server_set_notification(const char *char_path, g_variant_builder_add(outer_builder, "{sv}", "Unicast", g_variant_new("s", addr)); - BT_DBG("Set characteristic Notification \n"); + BT_DBG("Set characteristic Notification"); ret = g_dbus_connection_emit_signal(g_conn, NULL, char_path, "org.freedesktop.DBus.Properties", @@ -2278,3 +2694,650 @@ BT_EXPORT_API int bluetooth_gatt_server_set_notification(const char *char_path, return err; } + + +#if 0 +BT_EXPORT_API int bluetooth_gatt_register_application(int instance_id) +{ + BT_INIT_PARAMS(); + + if (!is_server_started) { + + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_GATT_REGISTER_APPLICATION) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have aprivilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; + } + + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + g_array_append_vals(in_param1, &instance_id, sizeof(int)); + + ret = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_REGISTER_APPLICATION, + in_param1, in_param2, in_param3, in_param4, &out_param); + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Register application failed"); + return ret; + } + is_server_started = true; + + return BLUETOOTH_ERROR_NONE; + } + + BT_INFO("Already RegisterApplication"); + return BLUETOOTH_ERROR_NONE; +} +#endif + +BT_EXPORT_API int bluetooth_gatt_server_init(int *instance_id, gatt_server_cb_func_ptr callback_ptr, + void *user_data) +{ + int ret = BLUETOOTH_ERROR_NONE; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + /* Register event handler for GATT */ + ret = _bt_register_event(BT_GATT_SERVER_EVENT, (void *)callback_ptr, user_data); + + if (ret != BLUETOOTH_ERROR_NONE && + ret != BLUETOOTH_ERROR_ALREADY_INITIALIZED) { + BT_ERR("Fail to init the event handler"); + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + goto done; + } + + ret = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_REGISTER, + in_param1, in_param2, in_param3, in_param4, &out_param); + + /* App ID -1 is invalid */ + if (ret != BLUETOOTH_ERROR_NONE) { + BT_INFO("GATT Server Registration failed result [%d]", ret); + *instance_id = -1; + } else { + *instance_id = g_array_index(out_param, int, 0); + BT_INFO("GATT Server Registered successfully: App Instance ID [%d]", *instance_id); + } + +done: + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + BT_INFO("GATT Server instance ID obtained [%d]", *instance_id); + return ret; +} + +BT_EXPORT_API int bluetooth_gatt_server_deinit(void) +{ + int ret; + BT_INFO("GATT Server Deinitialize"); + /* Unregister the event */ + ret = _bt_unregister_event(BT_GATT_SERVER_EVENT); + + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Fail to deinit the event handler"); + return ret; + } + + _bt_set_user_data(BT_GATT_SERVER, NULL, NULL); + + return ret; +} + +BT_EXPORT_API int bluetooth_gatt_server_add_service(const char *svc_uuid, int type, int numhandles, + int instance_id, int *service_handle) +{ + BT_CHECK_ENABLED(return); + BT_CHECK_PARAMETER(svc_uuid, return); + + int result; + char uuid[BT_GATT_ATT_UUID_LEN_MAX + 1]; + + g_strlcpy(uuid, svc_uuid, sizeof(uuid)); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &type, sizeof(int)); + g_array_append_vals(in_param2, &numhandles, sizeof(int)); + g_array_append_vals(in_param3, uuid, BT_GATT_ATT_UUID_LEN_MAX + 1); + g_array_append_vals(in_param4, &instance_id, sizeof(int)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_ADD_SERVICE, + in_param1, in_param2, in_param3, in_param4, &out_param); + + /* ATT handle 0 is reserved, hence it can not be used by app. + It will be used to indicate error in regsitering attribute */ + if (result != BLUETOOTH_ERROR_NONE) + *service_handle = 0; + else + *service_handle = g_array_index(out_param, int, 0); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_server_add_new_characteristic(const char *char_uuid, + const bluetooth_gatt_server_attribute_params_t *param, + int *char_handle) +{ + BT_CHECK_ENABLED(return); + BT_CHECK_PARAMETER(char_uuid, return); + BT_CHECK_PARAMETER(param, return); + + int result; + char uuid[BT_GATT_ATT_UUID_LEN_MAX + 1]; + + g_strlcpy(uuid, char_uuid, sizeof(uuid)); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, param, sizeof(bluetooth_gatt_server_attribute_params_t)); + g_array_append_vals(in_param2, uuid, BT_GATT_ATT_UUID_LEN_MAX + 1); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_ADD_CHARACTERISTIC, + in_param1, in_param2, in_param3, in_param4, &out_param); + + /* ATT handle 0 is reserved, hence it can not be used by app. + It will be used to indicate error in regsitering attribute */ + if (result != BLUETOOTH_ERROR_NONE) { + BT_ERR("GATT Server Add characteristic failed.. result [%d]", result); + *char_handle = 0; + } else { + *char_handle = g_array_index(out_param, int, 0); + BT_DBG("GATT Server Add characteristic success result [%d] char chandle [%d]", result, *char_handle); + } + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return result; +} + +BT_EXPORT_API int bluetooth_gatt_server_add_descriptor(const char *desc_uuid, bt_gatt_permission_t permissions, + int service_handle, int instance_id, int *descriptor_handle) +{ + BT_CHECK_ENABLED(return); + BT_CHECK_PARAMETER(desc_uuid, return); + + int result; + char uuid[BT_GATT_ATT_UUID_LEN_MAX + 1]; + + g_strlcpy(uuid, desc_uuid, sizeof(uuid)); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &service_handle, sizeof(int)); + g_array_append_vals(in_param2, &instance_id, sizeof(int)); + g_array_append_vals(in_param3, &permissions, sizeof(bt_gatt_permission_t)); + g_array_append_vals(in_param4, uuid, BT_GATT_ATT_UUID_LEN_MAX + 1); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_ADD_DESCRIPTOR, + in_param1, in_param2, in_param3, in_param4, &out_param); + + /* ATT handle 0 is reserved, hence it can not be used by app. + It will be used to indicate error in regsitering attribute */ + if (result != BLUETOOTH_ERROR_NONE) { + BT_ERR("GATT Server Add Descriptor failed.. result [%d] desc handle [%d]", result, *descriptor_handle); + *descriptor_handle = 0; + } else { + *descriptor_handle = g_array_index(out_param, int, 0); + BT_INFO("GATT Server Add Descriptor Successful.. result [%d] desc handle [%d]", result, *descriptor_handle); + } + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_server_start_service(int service_handle, int instance_id) +{ + BT_CHECK_ENABLED(return); + int result; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &service_handle, sizeof(int)); + g_array_append_vals(in_param2, &instance_id, sizeof(int)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_START_SERVICE, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_server_send_response(const bluetooth_gatt_server_response_params_t *param, + const bluetooth_gatt_att_data_t *value) +{ + BT_CHECK_PARAMETER(param, return); + BT_CHECK_PARAMETER(value, return); + BT_CHECK_ENABLED(return); + int result; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, value, sizeof(bluetooth_gatt_att_data_t)); + g_array_append_vals(in_param2, param, sizeof(bluetooth_gatt_server_response_params_t)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_SEND_RESPONSE, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; + +} + +BT_EXPORT_API int bluetooth_gatt_server_send_indication(bluetooth_device_address_t *addr_hex, + const bluetooth_gatt_server_indication_params_t *param, + const bluetooth_gatt_att_data_t *att_value) +{ + BT_CHECK_PARAMETER(param, return); + BT_CHECK_PARAMETER(att_value, return); + BT_CHECK_ENABLED(return); + int result = 0 ; + char addr[BLUETOOTH_ADDRESS_STRING_LENGTH] ; + int fd = -1; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, att_value, sizeof(bluetooth_gatt_att_data_t)); + g_array_append_vals(in_param2, param, sizeof(bluetooth_gatt_server_indication_params_t)); + g_array_append_vals(in_param3, addr_hex, sizeof(bluetooth_device_address_t)); + + _bt_convert_addr_type_to_string(addr, addr_hex->addr); + fd = bluetooth_get_characteristic_fd(param->atrribute_handle, addr); + + if (fd > -1) + result = bluetooth_gatt_write_characteristics_value_to_fd_(fd, att_value->data, att_value->length, NULL); + else + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_SEND_INDICATION, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_server_stop_service(int service_handle, int instance_id) +{ + BT_CHECK_ENABLED(return); + int result; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &service_handle, sizeof(int)); + g_array_append_vals(in_param2, &instance_id, sizeof(int)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_STOP_SERVICE, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_server_delete_service(int service_handle, int instance_id) +{ + BT_CHECK_ENABLED(return); + int result; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &service_handle, sizeof(int)); + g_array_append_vals(in_param2, &instance_id, sizeof(int)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_DELETE_SERVICE, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +/* Tizen Platform Specific */ +BT_EXPORT_API int bluetooth_gatt_server_update_characteristic(int instance_id, + const bluetooth_gatt_server_update_value_t *value) +{ + BT_CHECK_ENABLED(return); + BT_CHECK_PARAMETER(value, return); + int result; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &instance_id, sizeof(int)); + g_array_append_vals(in_param2, value, sizeof(bluetooth_gatt_server_update_value_t)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_UPDATE_VALUE, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_server_unregister(int instance_id) +{ + BT_CHECK_ENABLED(return); + int result; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &instance_id, sizeof(int)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_SERVER_DEREGISTER, + in_param1, in_param2, in_param3, in_param4, &out_param); + + if (result != BLUETOOTH_ERROR_NONE) + BT_INFO("GATT Server Unregistration failed result [%d]", result); + else + BT_INFO("GATT Server Unregistration successful"); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return result; +} + + +static gboolean bluetooth_gatt_server_acquire_channel_write_cb(GIOChannel *gio, + GIOCondition cond, gpointer data) +{ + + bluetooth_gatt_server_acquire_write_info_t *write_data = (bluetooth_gatt_server_acquire_write_info_t*)data; + + BT_DBG("FD io write data received [%s]", write_data->address); + + if (cond & G_IO_IN) { + GIOStatus status = G_IO_STATUS_NORMAL; + GError *err = NULL; + char *buffer = NULL; + gsize len = 0; + int BUF = BLUETOOTH_GATT_ATT_DATA_LENGTH_MAX; + + buffer = g_malloc0(BUF); + + status = g_io_channel_read_chars(gio, buffer, + BUF, &len, &err); + + if (status != G_IO_STATUS_NORMAL) { + BT_ERR("IO Channel read is failed with %d", status); + g_free(buffer); + if (err) { + BT_ERR("IO Channel read error [%s]", err->message); + if (status == G_IO_STATUS_ERROR) { + BT_ERR("cond : %d", cond); + g_error_free(err); + g_io_channel_shutdown(gio, TRUE, NULL); + g_io_channel_unref(gio); + + return FALSE; + } + g_error_free(err); + } + return FALSE; + } + + if (len > 0) { + bluetooth_gatt_server_write_requested_info_t write_info; + if (len < BLUETOOTH_GATT_ATT_DATA_LENGTH_MAX) + memcpy(write_info.data.data, buffer, len); + + write_info.length = len; + write_info.need_resp = false; + write_info.attribute_handle = write_data->attribute_handle; + //memcpy() + _bt_convert_addr_string_to_type(write_info.device_address.addr, write_data->address); + write_info.connection_id = write_data->connection_id; + write_info.offset = write_data->offset; + write_info.request_id = -2; + + bt_event_info_t *event_info; + event_info = _bt_event_get_cb_data(BT_GATT_SERVER_EVENT); + + if (event_info) { + + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, + BLUETOOTH_ERROR_NONE, &write_info, + event_info->cb, event_info->user_data); + } else { + BT_ERR("eventinfo failed"); + } + + + } + g_free(buffer); + + return TRUE; + } + + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + BT_ERR("Error : GIOCondition %d, ]", cond); + g_io_channel_shutdown(gio, TRUE, NULL); + g_io_channel_unref(gio); + + return FALSE; + } + + return TRUE; +} + +void bluetooth_gatt_server_send_acquire_write_response(GVariant * parameters) +{ + int con_id = -1; + int tran_id = -1; + int att_han = -1; + int pipefd[2] = {-1,}; + int mtu = -1; + int offset = -1; + char err_msg[512] = {'\0'}; + GIOChannel *channel = NULL; + char *addr = NULL; + int result = -1; + + g_variant_get(parameters, "(iiiiii&s)", + &result, + &con_id, + &tran_id, + &att_han, + &mtu, + &offset, + &addr); + + BT_DBG("GATT Server Acquire Write From Remote Client [%s]", addr); + BT_DBG("GATT ServerAcquire Conn ID: [%d]", con_id); + BT_DBG("GATT Server Acquire write att handle:[%d]", att_han); + BT_DBG("GATT Server Acquire Write Offset: [%d]", offset); + + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd) < 0) { + strerror_r(errno, err_msg, sizeof(err_msg)); + BT_ERR("socketpair(): %s", err_msg); + return ; + } + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + //param1 = g_array_new(TRUE, TRUE, sizeof(gchar)); + bluetooth_gatt_server_acquire_response_params_t data; + data.req_type = BLUETOOTH_GATT_REQUEST_TYPE_ACQUIRE_WRITE; + data.fd = pipefd[1]; + data.mtu = mtu; + data.request_id = tran_id; + + bluetooth_gatt_server_acquire_write_info_t *write_info = g_malloc0(sizeof(bluetooth_gatt_server_acquire_write_info_t)) ; + + write_info->attribute_handle = att_han; + write_info->connection_id = tran_id; + write_info->offset = offset; + + memcpy(write_info->address, addr , BLUETOOTH_ADDRESS_STRING_LENGTH); + + BT_INFO("FD read %d remote address [%s ] \n", pipefd[0], addr); + + + channel = g_io_channel_unix_new(pipefd[0]); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(channel, (G_IO_IN | G_IO_ERR | G_IO_HUP), + bluetooth_gatt_server_acquire_channel_write_cb, write_info); + + + GUnixFDList *fd_list = g_unix_fd_list_new(); + GError *error = NULL; + + g_unix_fd_list_append(fd_list, pipefd[1], &error); + g_assert_no_error(error); + close(pipefd[1]); + + g_array_append_vals(in_param1, &data, sizeof(bluetooth_gatt_server_acquire_response_params_t)); + + BT_INFO("Sending event BT_GATT_SERVER_ACQURE_WRITE_RESPONSE file descriptor value [%d] [ %s],", data.fd, addr); + + result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_GATT_SERVER_ACQURE_WRITE_RESPONSE, + in_param1, in_param2, in_param3, in_param4, fd_list, &out_param, NULL); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + +} + + + +void bluetooth_gatt_server_send_acquire_notify_response(GVariant * parameters, bt_event_info_t *event_info) +{ + int con_id = -1; + int tran_id = -1; + int att_han = -1; + int pipefd[2] = {-1,}; + int mtu = -1; + int offset = -1; + char err_msg[512] = {'\0'}; + GIOChannel *channel = NULL; + int result = -1; + int fd = -1; + bluetooth_gatt_acquire_notify_info_t *chr_info; + const char *address = NULL; + + g_variant_get(parameters, "(iiiiii&s)", + &result, + &con_id, + &tran_id, + &att_han, + &mtu, + &offset, + &address); + + BT_DBG("GATT ServerAcquire Conn ID: [%d]", con_id); + BT_DBG("GATT Server Acquire notify att handle:[%d]", att_han); + BT_DBG("GATT Server Acquire Notify Offset: [%d]", offset); + BT_DBG("GATT Server Acquire Notify address: [%s]", address); + + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd) < 0) { + strerror_r(errno, err_msg, sizeof(err_msg)); + BT_ERR("socketpair(): %s", err_msg); + return ; + } + + fd = pipefd[0]; + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + //param1 = g_array_new(TRUE, TRUE, sizeof(gchar)); + bluetooth_gatt_server_acquire_response_params_t data; + data.req_type = BLUETOOTH_GATT_REQUEST_TYPE_ACQUIRE_NOTIFY; + data.fd = pipefd[1]; + data.mtu = mtu; + data.request_id = tran_id; + + BT_INFO("FD write %d characterstics path \n", pipefd[0]); + + chr_info = bluetooth_get_characteristic_info_from_path(att_han); + if (!chr_info) { + chr_info = g_malloc0(sizeof(bluetooth_gatt_acquire_notify_info_t)); + chr_info->write_fd = fd; + chr_info->att_hand = att_han; + + gatt_characteristic_server_notify_list = g_slist_append(gatt_characteristic_server_notify_list, chr_info); + } else + chr_info->write_fd = fd; + + channel = g_io_channel_unix_new(fd); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(channel, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), + bluetooth_gatt_write_channel_watch_cb, chr_info); + + GUnixFDList *fd_list = g_unix_fd_list_new(); + GError *error = NULL; + + g_unix_fd_list_append(fd_list, pipefd[1], &error); + g_assert_no_error(error); + close(pipefd[1]); + + g_array_append_vals(in_param1, &data, sizeof(bluetooth_gatt_server_acquire_response_params_t)); + + BT_DBG("Sending event BT_GATT_SERVER_ACQUIRE_NOTIFY_RESPONSE file descriptor value [%d] ", data.fd); + + result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_GATT_SERVER_ACQUIRE_NOTIFY_RESPONSE, + in_param1, in_param2, in_param3, in_param4, fd_list, &out_param, NULL); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + + //send + if (result == BLUETOOTH_ERROR_NONE) { + BT_DBG("sending gatt server notification state changed event"); + bluetooth_gatt_server_notification_changed_t info; + bluetooth_device_address_t dev_address = { {0} }; + memset(&info, 0x00, sizeof(bluetooth_gatt_server_notification_changed_t)); + + _bt_convert_addr_string_to_type(dev_address.addr, address); + memcpy(info.device_address.addr, + dev_address.addr, + BLUETOOTH_ADDRESS_LENGTH); + info.handle = att_han; + info.notification = TRUE; + + _bt_gatt_server_event_cb(BLUETOOTH_EVENT_GATT_SERVER_NOTIFICATION_STATE_CHANGED, + result, &info, + event_info->cb, event_info->user_data); + + } +} + +void cleanup_gatt_acquire_fd(int handle) +{ + bluetooth_gatt_acquire_notify_info_t *chr_info = NULL; + + BT_INFO("+"); + + chr_info = bluetooth_get_characteristic_info_from_path(handle); + + if (chr_info != NULL) { + BT_INFO("GATT Server: acquire notification char info found"); + + if (chr_info->write_fd >= 0) { + BT_INFO("closing fd"); + close(chr_info->write_fd); + } + + BT_INFO("Removing char_info from the list"); + gatt_characteristic_server_notify_list = g_slist_remove(gatt_characteristic_server_notify_list, chr_info); + bluetooth_characteristic_info_free(chr_info); + } +}