RFCOMM socket : free connection info before sending callback
[platform/core/connectivity/bluetooth-frwk.git] / bt-api / bt-rfcomm-server.c
index b542170..04efc68 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include <string.h>
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
 #include <gio/gio.h>
 #include <gio/gunixfdlist.h>
 #include <sys/socket.h>
 #include "bt-request-sender.h"
 #include "bt-event-handler.h"
 
-#ifdef TIZEN_DPM_ENABLE
+#ifdef TIZEN_FEATURE_BT_DPM
 #include "bt-dpm.h"
 #endif
 
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
 
 static GSList *rfcomm_nodes;
 
 typedef struct {
+       bluetooth_device_address_t addr;
+       int fd;
+       guint watch_id;
+       gboolean disconnected;
+} rfcomm_conn_t;
+
+typedef struct {
        guint object_id;
        gchar *path;
        int id;
        char *uuid;
-       int fd;
-       GIOChannel *data_io;
-       guint data_id;
-       bluetooth_device_address_t addr;
+       GSList *rfcomm_conns;
        guint disconnect_idle_id;
 } rfcomm_info_t;
 
@@ -66,12 +70,17 @@ static rfcomm_info_t *__find_rfcomm_info_with_id(int id)
 static rfcomm_info_t *__find_rfcomm_info_with_fd(int fd)
 {
        GSList *l;
+       GSList *ll;
 
        for (l = rfcomm_nodes; l != NULL; l = l->next) {
                rfcomm_info_t *info = l->data;
 
-               if (info->fd == fd)
-                       return info;
+               for (ll = info->rfcomm_conns; ll; ll = ll->next) {
+                       rfcomm_conn_t *conn = ll->data;
+
+                       if (conn && conn->fd == fd)
+                               return info;
+               }
        }
 
        return NULL;
@@ -105,6 +114,37 @@ static rfcomm_info_t *__find_rfcomm_info_with_uuid(const char *uuid)
        return NULL;
 }
 
+static rfcomm_conn_t *__find_rfcomm_conn_with_fd(rfcomm_info_t *info,
+                                                     int fd)
+{
+       GSList *l;
+       rfcomm_conn_t *conn;
+
+       for (l = info->rfcomm_conns; l; l = l->next) {
+               conn = l->data;
+
+               if (conn && conn->fd == fd)
+                       return conn;
+       }
+
+       return NULL;
+}
+
+static void __rfcomm_remove_conn(rfcomm_info_t *info, int fd)
+{
+       rfcomm_conn_t *conn;
+
+       conn = __find_rfcomm_conn_with_fd(info, fd);
+       if (conn == NULL)
+               return;
+
+       info->rfcomm_conns = g_slist_remove(info->rfcomm_conns, conn);
+
+       if (conn->watch_id > 0)
+               g_source_remove(conn->watch_id);
+       g_free(conn);
+}
+
 gboolean _check_uuid_path(char *path, char *uuid)
 {
        rfcomm_info_t *info = NULL;
@@ -118,65 +158,89 @@ gboolean _check_uuid_path(char *path, char *uuid)
        return FALSE;
 }
 
-static void __connected_cb(rfcomm_info_t *info, bt_event_info_t *event_info)
+static void __connected_cb(rfcomm_info_t *info, rfcomm_conn_t *conn,
+                          bt_event_info_t *event_info)
 {
        bluetooth_rfcomm_connection_t conn_info;
 
        memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t));
+
        conn_info.device_role = RFCOMM_ROLE_SERVER;
        g_strlcpy(conn_info.uuid, info->uuid, BLUETOOTH_UUID_STRING_MAX);
-       conn_info.socket_fd = info->fd;
-       conn_info.device_addr = info->addr;
+       conn_info.socket_fd = conn->fd;
+       conn_info.device_addr = conn->addr;
        conn_info.server_id = info->id;
 
-       BT_INFO_C("Connected [RFCOMM Server]");
+       BT_INFO_C("### Connected [RFCOMM Server]");
        _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_CONNECTED,
                        BLUETOOTH_ERROR_NONE, &conn_info,
                        event_info->cb, event_info->user_data);
 }
 
-static gboolean __rfcomm_server_disconnect(rfcomm_info_t *info)
+static void __rfcomm_server_disconnect_conn(rfcomm_conn_t *conn,
+                                           rfcomm_info_t *info)
 {
        bluetooth_rfcomm_disconnection_t disconn_info;
-       int fd = info->fd;
        bt_event_info_t *event_info;
 
-       BT_INFO_C("Disconnected [RFCOMM Server]");
+       if (conn == NULL)
+               return;
 
-       if (info->data_id > 0) {
-               g_source_remove(info->data_id);
-               info->data_id = 0;
-       }
+       if (conn->disconnected == FALSE)
+               return;
 
-       if (info->fd >= 0) {
-               close(info->fd);
-               info->fd = -1;
+       if (conn->watch_id > 0) {
+               g_source_remove(conn->watch_id);
+               conn->watch_id = 0;
        }
 
-       if (info->data_io) {
-               g_io_channel_shutdown(info->data_io, TRUE, NULL);
-               g_io_channel_unref(info->data_io);
-               info->data_io = NULL;
-       }
-       info->disconnect_idle_id = 0;
        event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
-       if (event_info == NULL)
-               return FALSE;
+       if (event_info == NULL) {
+               BT_ERR("event_info is NULL");
+               __rfcomm_remove_conn(info, conn->fd);
+               return;
+       }
 
        memset(&disconn_info, 0x00, sizeof(bluetooth_rfcomm_disconnection_t));
        disconn_info.device_role = RFCOMM_ROLE_SERVER;
        g_strlcpy(disconn_info.uuid, info->uuid, BLUETOOTH_UUID_STRING_MAX);
-       disconn_info.socket_fd = fd;
-       disconn_info.device_addr = info->addr;
+       disconn_info.device_addr = conn->addr;
+
+       BT_INFO("Disconnected FD [%d]", conn->fd);
+       disconn_info.socket_fd = conn->fd;
+
+       __rfcomm_remove_conn(info, conn->fd);
 
        _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DISCONNECTED,
                        BLUETOOTH_ERROR_NONE, &disconn_info,
                        event_info->cb, event_info->user_data);
+}
+
+static gboolean __rfcomm_server_disconnect(rfcomm_info_t *info)
+{
+       BT_INFO_C("### Disconnected [RFCOMM Server]");
+
+       if (g_slist_find(rfcomm_nodes, info) == NULL) {
+               BT_INFO("rfcomm resource is already freed");
+               return FALSE;
+       }
+
+       info->disconnect_idle_id = 0;
+
+       g_slist_foreach(info->rfcomm_conns,
+                       (GFunc)__rfcomm_server_disconnect_conn, info);
 
        BT_DBG("-");
        return FALSE;
 }
 
+static gboolean __is_error_by_disconnect(GError *err)
+{
+       return !g_strcmp0(err->message, "Connection reset by peer") ||
+                       !g_strcmp0(err->message, "Connection timed out") ||
+                       !g_strcmp0(err->message, "Software caused connection abort");
+}
+
 static gboolean __data_received_cb(GIOChannel *chan, GIOCondition cond,
                                                                gpointer data)
 {
@@ -184,17 +248,18 @@ static gboolean __data_received_cb(GIOChannel *chan, GIOCondition cond,
        gsize len = 0;
        int result = BLUETOOTH_ERROR_NONE;
        rfcomm_info_t *info = data;
+       rfcomm_conn_t *conn;
        bt_event_info_t *event_info;
        bluetooth_rfcomm_received_data_t data_r;
        GIOStatus status = G_IO_STATUS_NORMAL;
        GError *err = NULL;
+       int fd;
 
        retv_if(info == NULL, FALSE);
 
-       event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
-
+       fd = g_io_channel_unix_get_fd(chan);
        if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
-               BT_ERR_C("RFComm Server  disconnected: %d", info->fd);
+               BT_ERR_C("RFComm Server disconnected: %d", fd);
 
                if (info->disconnect_idle_id > 0) {
                        BT_INFO("Disconnect idle still not process remove source");
@@ -202,6 +267,16 @@ static gboolean __data_received_cb(GIOChannel *chan, GIOCondition cond,
                        info->disconnect_idle_id = 0;
                }
 
+               conn = __find_rfcomm_conn_with_fd(info, fd);
+               if (conn == NULL) {
+                       BT_ERR("No Connection info found with FD [%d]", fd);
+                       return FALSE;
+               }
+
+               if (conn->disconnected == FALSE) {
+                       close(conn->fd);
+                       conn->disconnected = TRUE;
+               }
                __rfcomm_server_disconnect(info);
                return FALSE;
        }
@@ -209,39 +284,54 @@ static gboolean __data_received_cb(GIOChannel *chan, GIOCondition cond,
        buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1);
 
        status =  g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN,
-                       &len, &err);
+                                               &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 &&
-                           !g_strcmp0(err->message, "Connection reset by peer")) {
-                               BT_ERR("cond : %d", cond);
-                               g_error_free(err);
-                               if (info->disconnect_idle_id > 0) {
-                                       BT_INFO("Disconnect idle still not process remove source");
-                                       g_source_remove(info->disconnect_idle_id);
-                                       info->disconnect_idle_id = 0;
-                               }
-                               __rfcomm_server_disconnect(info);
+               if (!err)
+                       return TRUE;
+
+               BT_ERR("IO Channel read error [%s]", err->message);
+               if (status == G_IO_STATUS_ERROR &&
+                   __is_error_by_disconnect(err)) {
+                       BT_ERR("cond : %d", cond);
+                       g_error_free(err);
+
+                       if (info->disconnect_idle_id > 0) {
+                               BT_INFO("Disconnect idle still not process remove source");
+                               g_source_remove(info->disconnect_idle_id);
+                               info->disconnect_idle_id = 0;
+                       }
+
+                       conn = __find_rfcomm_conn_with_fd(info, fd);
+                       if (conn == NULL) {
+                               BT_ERR("No Connection info found with FD [%d]", fd);
                                return FALSE;
                        }
-                       g_error_free(err);
+
+                       if (conn->disconnected == FALSE) {
+                               close(conn->fd);
+                               conn->disconnected = TRUE;
+                       }
+                       __rfcomm_server_disconnect(info);
+                       return FALSE;
                }
+               g_error_free(err);
                return TRUE;
        }
 
        if (len == 0)
                BT_ERR("Length is zero");
 
+       event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
        if (event_info == NULL) {
+               BT_ERR("event_info is NULL. Unable to invoke the callback");
                g_free(buffer);
                return TRUE;
        }
 
-       data_r.socket_fd = info->fd;
+       data_r.socket_fd = fd;
        data_r.buffer_size = len;
        data_r.buffer = buffer;
 
@@ -257,30 +347,51 @@ static gboolean __data_received_cb(GIOChannel *chan, GIOCondition cond,
 int new_server_connection(const char *path, int fd, bluetooth_device_address_t *addr)
 {
        rfcomm_info_t *info;
+       rfcomm_conn_t *conn;
+       GIOChannel *data_io;
        bt_event_info_t *event_info;
 
-       BT_DBG("%s %d", path, fd);
+       BT_INFO("%s %d", path, fd);
 
        info = __find_rfcomm_info_with_path(path);
-       if (info == NULL)
+       if (info == NULL) {
+               BT_ERR("rfcomm info is NULL");
+               return -1;
+       }
+
+#ifdef TIZEN_FEATURE_BT_DPM
+       if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
+               char addr_str[20];
+
+               BT_ERR("Not allow to use SPP profile");
+
+               close(fd);
+               _bt_convert_addr_type_to_string(addr_str, addr->addr);
+               _bt_disconnect_ext_profile(addr_str, info->path);
+
                return -1;
+       }
+#endif
 
-       info->fd = fd;
-       memcpy(&info->addr, addr, sizeof(bluetooth_device_address_t));
+       conn = g_new0(rfcomm_conn_t, 1);
+       conn->fd = fd;
+       memcpy(&conn->addr, addr, sizeof(bluetooth_device_address_t));
+       info->rfcomm_conns = g_slist_append(info->rfcomm_conns, conn);
 
-       info->data_io = g_io_channel_unix_new(info->fd);
+       data_io = g_io_channel_unix_new(conn->fd);
 
-       g_io_channel_set_encoding(info->data_io, NULL, NULL);
-       g_io_channel_set_flags(info->data_io, G_IO_FLAG_NONBLOCK, NULL);
+       g_io_channel_set_encoding(data_io, NULL, NULL);
+       g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
 
-       info->data_id = g_io_add_watch(info->data_io,
+       conn->watch_id = g_io_add_watch(data_io,
                           G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                           __data_received_cb, info);
 
+       g_io_channel_unref(data_io);
+
        event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
-       if (event_info) {
-               __connected_cb(info, event_info);
-       }
+       if (event_info)
+               __connected_cb(info, conn, event_info);
 
        return 0;
 }
@@ -303,42 +414,48 @@ static rfcomm_info_t *__register_method()
                __rfcomm_delete_id(id);
                return NULL;
        }
-       info = g_new(rfcomm_info_t, 1);
+       info = g_new0(rfcomm_info_t, 1);
        info->object_id = (guint)object_id;
        info->path = path;
        info->id = id;
-       info->fd = -1;
 
        rfcomm_nodes = g_slist_append(rfcomm_nodes, info);
 
        return info;
 }
 
-static rfcomm_info_t *__register_method_2(const char *path,const char *bus_name)
+static rfcomm_info_t *__register_method_2(const char *path, const char *bus_name)
 {
        rfcomm_info_t *info;
        int object_id;
 
        object_id = _bt_register_new_conn_ex(path, bus_name, new_server_connection);
-       if (object_id < 0) {
+       if (object_id < 0)
                return NULL;
-       }
-       info = g_new(rfcomm_info_t, 1);
+
+       info = g_new0(rfcomm_info_t, 1);
        info->object_id = (guint)object_id;
        info->path = g_strdup(path);
        info->id = -1;
-       info->fd = -1;
 
        rfcomm_nodes = g_slist_append(rfcomm_nodes, info);
 
        return info;
 }
 
-void free_rfcomm_info(rfcomm_info_t *info)
+void free_rfcomm_conn(rfcomm_conn_t *conn, rfcomm_info_t *info)
 {
-       bt_event_info_t *event_info;
+       if (conn->disconnected == FALSE) {
+               close(conn->fd);
+               conn->disconnected = TRUE;
+       }
+       __rfcomm_server_disconnect_conn(conn, info);
+}
 
+void free_rfcomm_info(rfcomm_info_t *info)
+{
        BT_DBG("");
+
        if (info->disconnect_idle_id > 0) {
                BT_INFO("Disconnect idle still not process remove source");
                g_source_remove(info->disconnect_idle_id);
@@ -348,30 +465,60 @@ void free_rfcomm_info(rfcomm_info_t *info)
        __rfcomm_delete_id(info->id);
        _bt_unregister_gdbus(info->object_id);
 
-       if (info->fd >= 0) {
-               event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
-               if (event_info)
-                       BT_DBG("event type %d", event_info->event_type);
-               __rfcomm_server_disconnect(info);
-       }
+       g_slist_foreach(info->rfcomm_conns, (GFunc)free_rfcomm_conn, info);
 
        g_free(info->path);
        g_free(info->uuid);
        g_free(info);
 }
 
-void _bt_rfcomm_server_free_all()
+void _bt_rfcomm_server_free_all(void)
 {
        BT_DBG("Free all the servers");
 
        g_slist_free_full(rfcomm_nodes, (GDestroyNotify)free_rfcomm_info);
        rfcomm_nodes = NULL;
 }
+
+void _bt_rfcomm_server_disconnect_all(void)
+{
+       GSList *server;
+       GSList *conn;
+       char addr[20];
+
+       BT_INFO("### Disconnect all RFCOMM server connections");
+
+       for (server = rfcomm_nodes; server; ) {
+               rfcomm_info_t *info = server->data;
+
+               for (conn = info->rfcomm_conns; conn; conn = conn->next) {
+                       rfcomm_conn_t *conn_info = conn->data;
+
+                       if (conn_info == NULL)
+                               continue;
+
+                       if (conn_info->watch_id == 0 || conn_info->disconnected)
+                               continue;
+
+                       close(conn_info->fd);
+                       conn_info->disconnected = TRUE;
+
+                       _bt_convert_addr_type_to_string(addr,
+                                                       conn_info->addr.addr);
+                       _bt_disconnect_ext_profile(addr, info->path);
+               }
+
+               server = server->next;
+               __rfcomm_server_disconnect(info);
+       }
+
+       return;
+}
 #endif
 
 BT_EXPORT_API int bluetooth_rfcomm_create_socket(const char *uuid)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
 #else
        int result;
@@ -389,14 +536,14 @@ BT_EXPORT_API int bluetooth_rfcomm_create_socket(const char *uuid)
                return BLUETOOTH_ERROR_PERMISSION_DEINED;
        }
 
-#ifdef TIZEN_DPM_ENABLE
+#ifdef TIZEN_FEATURE_BT_DPM
        if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
                BT_ERR("Not allow to use SPP profile");
                return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
        }
 #endif
 
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        BT_INFO("<<<<<<<<< RFCOMM Create socket from app >>>>>>>>>");
        info = __register_method();
        if (info == NULL)
@@ -418,11 +565,10 @@ BT_EXPORT_API int bluetooth_rfcomm_create_socket(const char *uuid)
 
        BT_DBG("result: %x", result);
 
-       if (result == BLUETOOTH_ERROR_NONE) {
+       if (result == BLUETOOTH_ERROR_NONE)
                socket_fd = g_array_index(out_param, int, 0);
-       } else {
+       else
                BT_ERR("Fail to send request");
-       }
 
        BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
 
@@ -432,7 +578,7 @@ BT_EXPORT_API int bluetooth_rfcomm_create_socket(const char *uuid)
 
 BT_EXPORT_API int bluetooth_rfcomm_create_socket_ex(const char *uuid, const char *bus_name, const char *path)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
 
        BT_CHECK_ENABLED(return);
@@ -445,7 +591,7 @@ BT_EXPORT_API int bluetooth_rfcomm_create_socket_ex(const char *uuid, const char
                return BLUETOOTH_ERROR_PERMISSION_DEINED;
        }
 
-#ifdef TIZEN_DPM_ENABLE
+#ifdef TIZEN_FEATURE_BT_DPM
        if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
                BT_ERR("Not allow to use SPP profile");
                return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
@@ -466,9 +612,9 @@ BT_EXPORT_API int bluetooth_rfcomm_create_socket_ex(const char *uuid, const char
 }
 
 
-BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int socket_fd)
+BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int id)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
 #else
        int result;
@@ -482,19 +628,19 @@ BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int socket_fd)
                return BLUETOOTH_ERROR_PERMISSION_DEINED;
        }
 
-       if (socket_fd < 0) {
-               BT_ERR("Invalid FD");
+       if (id < 0) {
+               BT_ERR("Invalid ID");
                return BLUETOOTH_ERROR_INVALID_PARAM;
        }
 
-#ifdef RFCOMM_DIRECT
-       BT_INFO("<<<<<<<<< RFCOMM Remove socket request from app, fd=[%d] >>>>>>>>>>>", socket_fd);
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
+       BT_INFO("RFCOMM Remove socket request from app, ID [%d]", id);
 
-       info = __find_rfcomm_info_with_id(socket_fd);
+       info = __find_rfcomm_info_with_id(id);
        if (info == NULL)
                return BLUETOOTH_ERROR_INVALID_PARAM;
 
-       _bt_unregister_osp_server_in_agent(BT_RFCOMM_SERVER,info->uuid);
+       _bt_unregister_osp_server_in_agent(BT_RFCOMM_SERVER, info->uuid);
        _bt_unregister_profile(info->path);
 
        rfcomm_nodes = g_slist_remove(rfcomm_nodes, info);
@@ -505,16 +651,15 @@ BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int socket_fd)
        BT_INIT_PARAMS();
        BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
 
-       g_array_append_vals(in_param1, &socket_fd, sizeof(int));
+       g_array_append_vals(in_param1, &id, sizeof(int));
 
        result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_REMOVE_SOCKET,
                in_param1, in_param2, in_param3, in_param4, &out_param);
 
        BT_DBG("result: %x", result);
 
-       if (result == BLUETOOTH_ERROR_NONE) {
-               _bt_remove_server(socket_fd);
-       }
+       if (result == BLUETOOTH_ERROR_NONE)
+               _bt_remove_server(id);
 
        BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
 
@@ -524,7 +669,7 @@ BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int socket_fd)
 
 BT_EXPORT_API int bluetooth_rfcomm_remove_socket_ex(const char *uuid)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
 
        BT_CHECK_ENABLED(return);
@@ -535,7 +680,7 @@ BT_EXPORT_API int bluetooth_rfcomm_remove_socket_ex(const char *uuid)
                return BLUETOOTH_ERROR_PERMISSION_DEINED;
        }
 
-       BT_INFO("<<<<<<<<< RFCOMM Remove socket request from app, uuid=[%s] >>>>>>>>>>>", uuid);
+       BT_INFO("RFCOMM Remove socket request from app, uuid=[%s]", uuid);
 
        info = __find_rfcomm_info_with_uuid(uuid);
        if (info == NULL)
@@ -555,12 +700,13 @@ BT_EXPORT_API int bluetooth_rfcomm_remove_socket_ex(const char *uuid)
 
 BT_EXPORT_API int bluetooth_rfcomm_server_disconnect(int socket_fd)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
+       rfcomm_conn_t *conn;
 
        char address[20];
 
-       BT_INFO(">>>>>>>>RFCOMM server disconnect request from APP>>>>>>>>>");
+       BT_INFO("### Disconnect RFCOMM server");
        if (socket_fd < 0) {
                BT_ERR("Invalid FD");
                return BLUETOOTH_ERROR_INVALID_PARAM;
@@ -570,19 +716,24 @@ BT_EXPORT_API int bluetooth_rfcomm_server_disconnect(int socket_fd)
        if (info == NULL)
                return BLUETOOTH_ERROR_INVALID_PARAM;
 
-       if (info->data_io == NULL)
+       conn = __find_rfcomm_conn_with_fd(info, socket_fd);
+       if (conn == NULL)
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+
+       if (conn->watch_id == 0 || conn->disconnected)
                return BLUETOOTH_ERROR_NOT_CONNECTED;
 
-       g_io_channel_shutdown(info->data_io, TRUE, NULL);
-       g_io_channel_unref(info->data_io);
-       info->data_io = NULL;
+       close(conn->fd);
+       conn->disconnected = TRUE;
+
+       _bt_convert_addr_type_to_string(address, conn->addr.addr);
 
-       _bt_convert_addr_type_to_string(address, info->addr.addr);
        BT_DBG("Address %s", address);
-       _bt_disconnect_profile(address, info->uuid, NULL,NULL);
+       _bt_disconnect_ext_profile(address, info->path);
 
-       info->disconnect_idle_id = g_idle_add((GSourceFunc)
-                                                       __rfcomm_server_disconnect, info);
+       if (info->disconnect_idle_id == 0)
+               info->disconnect_idle_id = g_idle_add(
+                               (GSourceFunc)__rfcomm_server_disconnect, info);
        BT_DBG("-");
 
        return BLUETOOTH_ERROR_NONE;
@@ -628,9 +779,8 @@ BT_EXPORT_API gboolean bluetooth_rfcomm_is_server_uuid_available(const char *uui
 
        BT_DBG("result: %x", result);
 
-       if (result == BLUETOOTH_ERROR_NONE) {
+       if (result == BLUETOOTH_ERROR_NONE)
                available = g_array_index(out_param, gboolean, 0);
-       }
 
        BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
 
@@ -642,25 +792,28 @@ BT_EXPORT_API gboolean bluetooth_rfcomm_is_server_uuid_available(const char *uui
 BT_EXPORT_API int bluetooth_rfcomm_server_is_connected(const bluetooth_device_address_t *device_address, gboolean *connected)
 {
        GSList *l;
+       GSList *ll;
        rfcomm_info_t *info;
-       char connected_addr[BT_ADDRESS_STRING_SIZE] = { 0 };
-       char input_addr[BT_ADDRESS_STRING_SIZE] = { 0 };
+       rfcomm_conn_t *conn;
 
        BT_CHECK_PARAMETER(device_address, return);
        BT_CHECK_PARAMETER(connected, return);
 
-       _bt_convert_addr_type_to_string(input_addr, (unsigned char *)device_address->addr);
-
        *connected = FALSE;
 
-       for (l = rfcomm_nodes; l != NULL; l = l->next) {
+       for (l = rfcomm_nodes; l; l = l->next) {
                info = l->data;
 
-               if (info == NULL)
+               if (info == NULL || info->rfcomm_conns == NULL)
                        continue;
-               _bt_convert_addr_type_to_string(connected_addr, info->addr.addr);
 
-               if (g_strcmp0(connected_addr, input_addr) == 0) {
+               for (ll = info->rfcomm_conns; ll; ll = ll->next) {
+                       conn = ll->data;
+
+                       if (memcmp(device_address, &conn->addr,
+                                       sizeof(bluetooth_device_address_t)))
+                               continue;
+
                        *connected = TRUE;
                        return BLUETOOTH_ERROR_NONE;
                }
@@ -669,9 +822,9 @@ BT_EXPORT_API int bluetooth_rfcomm_server_is_connected(const bluetooth_device_ad
        return BLUETOOTH_ERROR_NONE;
 }
 
-BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int socket_fd, int max_pending_connection)
+BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int id, int max_pending_connection)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
 #else
        int result;
@@ -679,23 +832,22 @@ BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int socket_fd, int max_pend
 #endif
 
        BT_CHECK_ENABLED(return);
+       if (id < 0) {
+               BT_ERR("Invalid ID");
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
 
-#ifdef TIZEN_DPM_ENABLE
+#ifdef TIZEN_FEATURE_BT_DPM
        if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
                BT_ERR("Not allow to use SPP profile");
                return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
        }
 #endif
 
-       if (socket_fd < 0) {
-               BT_ERR("Invalid FD");
-               return BLUETOOTH_ERROR_INVALID_PARAM;
-       }
-
-#ifdef RFCOMM_DIRECT
-       BT_INFO("<<<<<<<<< RFCOMM Listen & accept from app >>>>>>>>>>>");
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
+       BT_INFO("RFCOMM Listen & accept from app");
 
-       info = __find_rfcomm_info_with_id(socket_fd);
+       info = __find_rfcomm_info_with_id(id);
        if (info == NULL)
                return BLUETOOTH_ERROR_INVALID_PARAM;
 
@@ -717,7 +869,7 @@ BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int socket_fd, int max_pend
        BT_INIT_PARAMS();
        BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
 
-       g_array_append_vals(in_param1, &socket_fd, sizeof(int));
+       g_array_append_vals(in_param1, &id, sizeof(int));
        g_array_append_vals(in_param2, &max_pending_connection, sizeof(int));
        g_array_append_vals(in_param3, &native_service, sizeof(gboolean));
 
@@ -732,21 +884,23 @@ BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int socket_fd, int max_pend
 #endif
 }
 
-BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept_ex(const char *uuid, int max_pending_connection, const char *bus_name, const char *path)
+BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept_ex(const char *uuid,
+                                       int max_pending_connection,
+                                       const char *bus_name, const char *path)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
 
        BT_CHECK_ENABLED(return);
 
-#ifdef TIZEN_DPM_ENABLE
+#ifdef TIZEN_FEATURE_BT_DPM
        if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
                BT_ERR("Not allow to use SPP profile");
                return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
        }
 #endif
 
-       BT_INFO("<<<<<<<<< RFCOMM Listen & accept from app >>>>>>>>>>>");
+       BT_INFO("RFCOMM Listen & accept from app");
 
        info = __find_rfcomm_info_with_uuid(uuid);
        if (info == NULL)
@@ -771,9 +925,9 @@ BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept_ex(const char *uuid, int ma
 #endif
 }
 
-BT_EXPORT_API int bluetooth_rfcomm_listen(int socket_fd, int max_pending_connection)
+BT_EXPORT_API int bluetooth_rfcomm_listen(int id, int max_pending_connection)
 {
-#ifdef RFCOMM_DIRECT
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
        rfcomm_info_t *info;
 #else
        int result;
@@ -781,23 +935,22 @@ BT_EXPORT_API int bluetooth_rfcomm_listen(int socket_fd, int max_pending_connect
 #endif
 
        BT_CHECK_ENABLED(return);
+       if (id < 0) {
+               BT_ERR("Invalid ID");
+               return BLUETOOTH_ERROR_INVALID_PARAM;
+       }
 
-#ifdef TIZEN_DPM_ENABLE
+#ifdef TIZEN_FEATURE_BT_DPM
        if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
                BT_ERR("Not allow to use SPP profile");
                return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
        }
 #endif
 
-       if (socket_fd < 0) {
-               BT_ERR("Invalid FD");
-               return BLUETOOTH_ERROR_INVALID_PARAM;
-       }
-
-#ifdef RFCOMM_DIRECT
-       BT_INFO("<<<<<<<<< RFCOMM Listen >>>>>>>>>>>");
+#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
+       BT_INFO("RFCOMM Listen");
 
-       info = __find_rfcomm_info_with_id(socket_fd);
+       info = __find_rfcomm_info_with_id(id);
        if (info == NULL)
                return BLUETOOTH_ERROR_INVALID_PARAM;
 
@@ -817,13 +970,13 @@ BT_EXPORT_API int bluetooth_rfcomm_listen(int socket_fd, int max_pending_connect
                return result;
 
        return _bt_register_osp_server_in_agent(BT_RFCOMM_SERVER, info->uuid,
-                                               info->path, socket_fd);
+                                               info->path, id);
 
 #else
        BT_INIT_PARAMS();
        BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
 
-       g_array_append_vals(in_param1, &socket_fd, sizeof(int));
+       g_array_append_vals(in_param1, &id, sizeof(int));
        g_array_append_vals(in_param2, &max_pending_connection, sizeof(int));
        g_array_append_vals(in_param3, &native_service, sizeof(gboolean));
 
@@ -832,9 +985,8 @@ BT_EXPORT_API int bluetooth_rfcomm_listen(int socket_fd, int max_pending_connect
 
        BT_DBG("result: %x", result);
 
-        if (result == BLUETOOTH_ERROR_NONE) {
-                _bt_add_server(socket_fd);
-        }
+       if (result == BLUETOOTH_ERROR_NONE)
+               _bt_add_server(id);
 
        BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
 
@@ -848,7 +1000,7 @@ BT_EXPORT_API int bluetooth_rfcomm_accept_connection(int server_fd)
 
        BT_CHECK_ENABLED(return);
 
-#ifdef TIZEN_DPM_ENABLE
+#ifdef TIZEN_FEATURE_BT_DPM
        if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
                BT_ERR("Not allow to use SPP profile");
                return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;