Fix the memory leak
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / bluez_hal / src / bt-hal-gatt-server.c
index 2f093c3..776a4d6 100644 (file)
@@ -64,13 +64,19 @@ static GDBusConnection *g_conn = NULL;
 static GDBusNodeInfo *manager_node_info = NULL;
 static guint manager_id;
 
-/* Global handles which needs to be incremented during each addition */
-#define SERVICE_HANDLE_NUM 100
-#define CHAR_HANDLE_NUM 200
-#define DESC_HANDLE_NUM 300
-static int gatt_service_handle = SERVICE_HANDLE_NUM;
-static int gatt_char_handle = CHAR_HANDLE_NUM;
-static int gatt_desc_handle = DESC_HANDLE_NUM;
+#define GATT_HANDLE_MAX_NUM 100 /* Not defined in spec, implementation dependent */
+#define SERV_HANDLE_NUM (GATT_HANDLE_MAX_NUM)
+#define CHAR_HANDLE_NUM (SERV_HANDLE_NUM + GATT_HANDLE_MAX_NUM)
+#define DESC_HANDLE_NUM (CHAR_HANDLE_NUM + GATT_HANDLE_MAX_NUM)
+typedef enum {
+       BT_GATT_TYPE_SERV,
+       BT_GATT_TYPE_CHAR,
+       BT_GATT_TYPE_DESC,
+       BT_GATT_TYPE_MAX
+} bt_gatt_type_e;
+static int assigned_handle[BT_GATT_TYPE_MAX];
+static gboolean gatt_handle_used[BT_GATT_TYPE_MAX][GATT_HANDLE_MAX_NUM];
+static int gatt_handle_base[BT_GATT_TYPE_MAX] = {SERV_HANDLE_NUM, CHAR_HANDLE_NUM, DESC_HANDLE_NUM};
 
 struct gatt_service_info {
        gchar *serv_path;
@@ -262,6 +268,7 @@ static const gchar characteristics_introspection_xml[] =
 "               <arg type='u' name='id' direction='in'/>"
 "               <arg type='q' name='offset' direction='in'/>"
 "               <arg type='b' name='response_needed' direction='in'/>"
+"               <arg type='b' name='prep_authorize' direction='in'/>"
 "               <arg type='ay' name='value' direction='in'/>"
 "        </method>"
 "       <method name ='AcquireWrite'>"
@@ -320,6 +327,7 @@ static const gchar descriptor_introspection_xml[] =
 "               <arg type='u' name='id' direction='in'/>"
 "               <arg type='q' name='offset' direction='in'/>"
 "               <arg type='b' name='response_needed' direction='in'/>"
+"               <arg type='b' name='prep_authorize' direction='in'/>"
 "               <arg type='ay' name='value' direction='in'/>"
 "        </method>"
 "  </interface>"
@@ -366,6 +374,9 @@ void _bt_hal_gatt_server_init(void)
        assigned_id = 0;
        memset(instance_id_used, 0x00, sizeof(instance_id_used));
 
+       assigned_handle[BT_GATT_TYPE_SERV] = assigned_handle[BT_GATT_TYPE_CHAR] = assigned_handle[BT_GATT_TYPE_DESC] = -1;
+       memset(gatt_handle_used, 0x00, sizeof(gatt_handle_used));
+
        g_slist_free_full(gatt_server_apps, (GDestroyNotify)__bt_free_gatt_server_app);
        gatt_server_apps = NULL;
 
@@ -412,6 +423,52 @@ static void __bt_hal_gatt_delete_id(int instance_id)
        instance_id_used[instance_id] = FALSE;
 }
 
+static int __bt_hal_assign_gatt_handle(bt_gatt_type_e type)
+{
+       int index;
+
+       index = assigned_handle[type] + 1;
+
+       if (index >= GATT_HANDLE_MAX_NUM)
+               index = 0;
+
+       while (gatt_handle_used[type][index] == TRUE) {
+               if (index == assigned_handle[type]) {
+                       /* No available handle */
+                       ERR("All handle is used");
+                       return -1;
+               }
+
+               index++;
+
+               if (index >= GATT_HANDLE_MAX_NUM)
+                       index = 0;
+       }
+
+       assigned_handle[type] = index;
+       gatt_handle_used[type][index] = TRUE;
+
+       return assigned_handle[type] + gatt_handle_base[type];
+}
+
+static void __bt_hal_free_gatt_handle(bt_gatt_type_e type, int handle)
+{
+       int index;
+
+       if (type >= BT_GATT_TYPE_MAX) {
+               ERR("Invalid type");
+               return;
+       }
+
+       index = handle - gatt_handle_base[type];
+       if (index < 0 || index >= GATT_HANDLE_MAX_NUM) {
+               ERR("Invalid handle: %d(type: %d)", handle, type);
+               return;
+       }
+
+       gatt_handle_used[type][index] = FALSE;
+}
+
 static GSList *_bt_get_service_list_from_server(int instance)
 {
        GSList *l;
@@ -1116,6 +1173,7 @@ static void __bt_gatt_desc_method_call(GDBusConnection *connection,
                guint req_id = 0;
                guint16 offset = 0;
                gboolean response_needed = FALSE;
+               gboolean prep_authorize = FALSE;
                struct hal_ev_gatt_server_write_req ev;
                int desc_hdl = -1;
                int len;
@@ -1130,10 +1188,13 @@ static void __bt_gatt_desc_method_call(GDBusConnection *connection,
                DBG("Application path = %s", object_path);
                DBG("Sender = %s", sender);
 
-               g_variant_get(parameters, "(&suqb@ay)",
-                               &addr, &req_id, &offset, &response_needed, &var);
+               g_variant_get(parameters, "(&suqbb@ay)",
+                               &addr, &req_id, &offset, &response_needed, &prep_authorize, &var);
                DBG("Request id = %u, Offset = %u", req_id, offset);
 
+               if (prep_authorize)
+                       DBG("prep_authorize = true");
+
                /* Check if device is already in connected list */
                conn_info = __bt_find_remote_gatt_client_info(addr);
 
@@ -1261,6 +1322,7 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection,
                guint req_id = 0;
                guint16 offset = 0;
                gboolean response_needed = FALSE;
+               gboolean prep_authorize = FALSE;
                struct hal_ev_gatt_server_write_req ev;
                int char_hdl = -1;
                int len;
@@ -1273,10 +1335,13 @@ static void __bt_gatt_char_method_call(GDBusConnection *connection,
 
                DBG("WriteValue : Application path %s, sender %s", object_path, sender);
 
-               g_variant_get(parameters, "(&suqb@ay)",
-                               &addr, &req_id, &offset, &response_needed, &var);
+               g_variant_get(parameters, "(&suqbb@ay)",
+                               &addr, &req_id, &offset, &response_needed, &prep_authorize, &var);
                DBG("Request id = %u, Offset = %u", req_id, offset);
 
+               if (prep_authorize)
+                       DBG("prep_authorize = true");
+
                svc_info = __bt_gatt_find_gatt_service_from_char(object_path, &char_hdl);
 
                /* Check if device is already in connected list */
@@ -2161,20 +2226,23 @@ static int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id
        gboolean svc_primary = TRUE;
        GError *error = NULL;
        hal_gatt_service_added *user_data = NULL;
+       int service_handle = 0;
        DBG("Service add to DBUS slot [%d]", slot);
 
-       DBG("Add new GATT Service: Current GATT Service handle [%d]", gatt_service_handle);
-       if (gatt_service_handle >= CHAR_HANDLE_NUM) {
-               ERR("Exceeded the number of service");
+       service_handle = __bt_hal_assign_gatt_handle(BT_GATT_TYPE_SERV);
+       if (service_handle == -1) {
+               ERR("Too many gatt service handles are created");
                return BT_STATUS_FAIL;
        }
-       path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, ++gatt_service_handle);
+
+       path = g_strdup_printf("%s"GATT_SERV_OBJECT_PATH"%d", app_path, service_handle);
        DBG("gatt service path is [%s]", path);
 
        node_info = __bt_gatt_create_method_node_info(
                        service_introspection_xml);
        if (node_info == NULL) {
                g_free(path);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_SERV, service_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2187,6 +2255,7 @@ static int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id
                ERR("failed to register: %s", error->message);
                g_error_free(error);
                g_free(path);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_SERV, service_handle);
                return BT_STATUS_FAIL;
        }
        /* Add object_id/gatt service information; it's required at the time of
@@ -2199,8 +2268,8 @@ static int __bt_hal_add_service_to_dbus(char *app_path, int slot, btgatt_srvc_id
        serv_info->service_uuid = __bt_hal_convert_uuid_to_string(&srvc_id->id.uuid);//g_strdup(btuuid2str(srvc_id->id.uuid.uu));
        serv_info->is_svc_registered = FALSE;
        serv_info->is_svc_primary = svc_primary;
-       DBG("Service Handle to be added is [%d]", gatt_service_handle);
-       serv_info->service_handle = gatt_service_handle;
+       DBG("Service Handle to be added is [%d]", service_handle);
+       serv_info->service_handle = service_handle;
 
        /* Update service in GATT Server service List */
        gatt_services = g_slist_append(gatt_services, serv_info);
@@ -2534,6 +2603,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
        int flag_count = 0;
        hal_gatt_char_added *user_data = NULL;
        int *app_id;
+       int char_handle = 0;
 
        CHECK_BTGATT_INIT();
        DBG("Add new characteristic to GATT Service handle [%d]", service_handle);
@@ -2543,18 +2613,21 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
        if (serv_info == NULL)
                return BT_STATUS_FAIL;
 
-       DBG("Add new GATT characteristic: Current GATT char handle [%d]", gatt_char_handle);
-       if (gatt_char_handle >= DESC_HANDLE_NUM) {
-               ERR("Exceeded the number of characteristic");
+       char_handle = __bt_hal_assign_gatt_handle(BT_GATT_TYPE_CHAR);
+       if (char_handle == -1) {
+               ERR("Too many gatt char handles are created");
                return BT_STATUS_FAIL;
        }
-       path = g_strdup_printf("%s/characteristic%d", serv_info->serv_path, ++gatt_char_handle);
+
+       DBG("Add new GATT characteristic: Current GATT char handle [%d]", char_handle);
+       path = g_strdup_printf("%s/characteristic%d", serv_info->serv_path, char_handle);
        DBG("gatt characteristic path is [%s]", path);
 
        node_info = __bt_gatt_create_method_node_info(
                        characteristics_introspection_xml);
        if (node_info == NULL) {
                g_free(path);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_CHAR, char_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2571,6 +2644,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
                g_error_free(error);
                g_free(path);
                g_free(app_id);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_CHAR, char_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2595,7 +2669,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
 
 
        char_info->flags_length = flag_count;
-       char_info->char_handle = gatt_char_handle;
+       char_info->char_handle = char_handle;
 
 
        builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
@@ -2647,7 +2721,7 @@ static bt_status_t gatt_server_add_characteristic(int slot, int service_handle,
        /* Send Service handle to application */
        user_data = g_malloc0(sizeof(hal_gatt_char_added));
        user_data->srvc_hdl = serv_info->service_handle;
-       user_data->char_hdl = gatt_char_handle;
+       user_data->char_hdl = char_handle;
        user_data->instance_data = slot;
        memcpy(user_data->uuid.uu, uuid->uu, sizeof(uuid->uu));
        g_idle_add(__bt_hal_gatt_char_added_cb, (gpointer)user_data);
@@ -2695,6 +2769,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
        int flag_count = 0;
        int *app_id;
        hal_gatt_desc_added *user_data = NULL;
+       int desc_handle = 0;
 
        /* Fetch service data for the GATT server */
        serv_info = __bt_gatt_find_gatt_service_info(slot, service_handle);
@@ -2725,9 +2800,15 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
                return BT_STATUS_FAIL;
        }
 
-       DBG("Add new Descriptor: Current GATT desc handle [%d]", gatt_desc_handle);
+       desc_handle = __bt_hal_assign_gatt_handle(BT_GATT_TYPE_DESC);
+       if (desc_handle == -1) {
+               ERR("Too many gatt desc handles are created");
+               g_free(serv_path);
+               return BT_STATUS_FAIL;
+       }
 
-       path = g_strdup_printf("%s/descriptor%d", char_path, ++gatt_desc_handle);
+       DBG("Add new Descriptor: Current GATT desc handle [%d]", desc_handle);
+       path = g_strdup_printf("%s/descriptor%d", char_path, desc_handle);
        DBG("gatt descriptor path is [%s]", path);
 
        app_id = g_malloc0(sizeof(int));
@@ -2745,6 +2826,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
                g_strfreev(line_argv);
                g_free(serv_path);
                g_free(app_id);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_DESC, desc_handle);
                return BT_STATUS_FAIL;
        }
 
@@ -2760,7 +2842,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
                desc_info->desc_flags[i] = desc_flags[i];
 
        desc_info->flags_length = flag_count;
-       desc_info->desc_handle = gatt_desc_handle;
+       desc_info->desc_handle = desc_handle;
 
 
        builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
@@ -2804,7 +2886,7 @@ static bt_status_t gatt_server_add_descriptor(int slot, int service_handle, bt_u
        /* Send descriptor handle to application */
        user_data = g_malloc0(sizeof(hal_gatt_desc_added));
        user_data->srvc_hdl = serv_info->service_handle;
-       user_data->desc_hdl = gatt_desc_handle;
+       user_data->desc_hdl = desc_handle;
        user_data->instance_data = slot;
        memcpy(user_data->uuid.uu, uuid->uu, sizeof(uuid->uu));
        g_idle_add(__bt_hal_gatt_desc_added_cb, (gpointer)user_data);
@@ -3008,6 +3090,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle)
 
                        /* list remove & free */
                        char_info->desc_data = g_slist_remove(char_info->desc_data, desc_info);
+                       __bt_hal_free_gatt_handle(BT_GATT_TYPE_DESC, desc_info->desc_handle);
                        __bt_hal_gatt_free_descriptor_info(desc_info);
                }
 
@@ -3026,6 +3109,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle)
 
                /* list remove & free */
                serv_info->char_data = g_slist_remove(serv_info->char_data, char_info);
+               __bt_hal_free_gatt_handle(BT_GATT_TYPE_CHAR, char_info->char_handle);
                __bt_hal_gatt_free_characteristic_info(char_info);
        }
 
@@ -3047,6 +3131,7 @@ static bt_status_t gatt_server_delete_service(int server_if, int service_handle)
 
        /* Remove from global list */
        gatt_services = g_slist_remove(gatt_services, serv_info);
+       __bt_hal_free_gatt_handle(BT_GATT_TYPE_SERV, serv_info->service_handle);
        INFO("After removing from global list total service dount [%d]", g_slist_length(gatt_services));
 
        /* Remove from GATT Server's list of services */