X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-api%2Fbt-rfcomm-server.c;h=ee29302e034e3e4173e73a98db9d6b2900f29a37;hb=1fa07edcd0e77a445700975773db3300f556caf5;hp=5396f700107b1e0d7674de07a9b5e28dbd78b863;hpb=008772c3a4c662bd78b145032df59153d96517be;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-api/bt-rfcomm-server.c b/bt-api/bt-rfcomm-server.c index 5396f70..ee29302 100644 --- a/bt-api/bt-rfcomm-server.c +++ b/bt-api/bt-rfcomm-server.c @@ -1,13 +1,11 @@ /* - * bluetooth-frwk - * - * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,6 +16,11 @@ */ #include +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT +#include +#include +#include +#endif #include "bluetooth-api.h" #include "bt-internal-types.h" @@ -26,82 +29,1317 @@ #include "bt-request-sender.h" #include "bt-event-handler.h" +#ifdef TIZEN_FEATURE_BT_DPM +#include "bt-dpm.h" +#endif -BT_EXPORT_API int bluetooth_rfcomm_create_socket(const char *uuid) +#define BLUETOOTH_SOCK_CONNECT_INFO_LEN 16 + +#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; + GSList *rfcomm_conns; + guint disconnect_idle_id; +} rfcomm_info_t; + +static rfcomm_info_t *__find_rfcomm_info_with_id(int id) +{ + GSList *l; + + for (l = rfcomm_nodes; l != NULL; l = l->next) { + rfcomm_info_t *info = l->data; + + if (info->id == id) + return info; + } + + return NULL; +} + +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; + + for (ll = info->rfcomm_conns; ll; ll = ll->next) { + rfcomm_conn_t *conn = ll->data; + + if (conn && conn->fd == fd) + return info; + } + } + + return NULL; +} + +static rfcomm_info_t *__find_rfcomm_info_with_path(const gchar *path) +{ + GSList *l; + + for (l = rfcomm_nodes; l != NULL; l = l->next) { + rfcomm_info_t *info = l->data; + + if (g_strcmp0(info->path, path) == 0) + return info; + } + + return NULL; +} + +static rfcomm_info_t *__find_rfcomm_info_with_uuid(const char *uuid) +{ + GSList *l; + + for (l = rfcomm_nodes; l != NULL; l = l->next) { + rfcomm_info_t *info = l->data; + + if (g_strcmp0(info->uuid, uuid) == 0) + return info; + } + + 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; + info = __find_rfcomm_info_with_path(path); + if (!info) + return FALSE; + + if (strcmp(info->uuid, uuid) == 0) + return TRUE; + + return FALSE; +} + +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 = conn->fd; + conn_info.device_addr = conn->addr; + conn_info.server_id = info->id; + + 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 void __rfcomm_server_disconnect_conn(rfcomm_conn_t *conn, + rfcomm_info_t *info) +{ + bluetooth_rfcomm_disconnection_t disconn_info; + bt_event_info_t *event_info; + + if (conn == NULL) + return; + + if (conn->disconnected == FALSE) + return; + + if (conn->watch_id > 0) { + g_source_remove(conn->watch_id); + conn->watch_id = 0; + } + + event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT); + 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.device_addr = conn->addr; + + BT_INFO("Disconnected FD [%d]", conn->fd); + disconn_info.socket_fd = conn->fd; + + _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DISCONNECTED, + BLUETOOTH_ERROR_NONE, &disconn_info, + event_info->cb, event_info->user_data); + + __rfcomm_remove_conn(info, conn->fd); +} + +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) +{ + char *buffer = NULL; + 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); + + 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", fd); + + 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; + } + + if (conn->disconnected == FALSE) { + close(conn->fd); + conn->disconnected = TRUE; + } + __rfcomm_server_disconnect(info); + return FALSE; + } + + buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1); + + status = g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN, + &len, &err); + if (status != G_IO_STATUS_NORMAL) { + BT_ERR("IO Channel read is failed with %d", status); + + g_free(buffer); + 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; + } + + 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 = fd; + data_r.buffer_size = len; + data_r.buffer = buffer; + + _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DATA_RECEIVED, + result, &data_r, + event_info->cb, event_info->user_data); + + g_free(buffer); + + return TRUE; +} + +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_INFO("%s %d", path, fd); + + info = __find_rfcomm_info_with_path(path); + 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 + + 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); + + data_io = g_io_channel_unix_new(conn->fd); + + g_io_channel_set_encoding(data_io, NULL, NULL); + g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL); + + 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, conn, event_info); + + return 0; +} + +static rfcomm_info_t *__register_method() +{ + gchar *path; + rfcomm_info_t *info; + int object_id; + int id; + + id = __rfcomm_assign_id(); + if (id < 0) + return NULL; + + path = g_strdup_printf("/org/socket/server/%d/%d", getpid(), id); + + object_id = _bt_register_new_conn(path, new_server_connection); + if (object_id < 0) { + __rfcomm_delete_id(id); + return NULL; + } + info = g_new0(rfcomm_info_t, 1); + info->object_id = (guint)object_id; + info->path = path; + info->id = id; + + rfcomm_nodes = g_slist_append(rfcomm_nodes, info); + + return info; +} + +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) + return NULL; + + info = g_new0(rfcomm_info_t, 1); + info->object_id = (guint)object_id; + info->path = g_strdup(path); + info->id = -1; + + rfcomm_nodes = g_slist_append(rfcomm_nodes, info); + + return info; +} + +void free_rfcomm_conn(rfcomm_conn_t *conn, rfcomm_info_t *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); + info->disconnect_idle_id = 0; + } + + __rfcomm_delete_id(info->id); + _bt_unregister_gdbus(info->object_id); + + 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_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; +} +#else + +#define BT_RFCOMM_SERVER_ID_MAX 254 + +typedef struct { + char addr[BT_ADDRESS_STRING_SIZE]; + int sock_fd; + int watch_id; + int server_id; +} rfcomm_remote_client_info_t; + +typedef struct { + char uuid[BLUETOOTH_UUID_STRING_MAX]; + int server_id; + int server_fd; + int watch_id; + int max_pending_conn; + gboolean auto_accept; + char pending_addr[BT_ADDRESS_STRING_SIZE]; + GSList *conn_list; +} rfcomm_server_info_t; + +static GSList *rfcomm_servers; +static gboolean id_used[BT_RFCOMM_SERVER_ID_MAX]; +int latest_id = 0; + +int __rfcomm_assign_server_id(void) +{ + int index; + + BT_DBG("latest_id: %d", latest_id); + + index = latest_id + 1; + + if (index >= BT_RFCOMM_SERVER_ID_MAX) + index = 0; + + BT_DBG("index: %d", index); + + while (id_used[index] == TRUE) { + if (index == latest_id) { + /* No available ID */ + BT_ERR("All request ID is used"); + return -1; + } + + index++; + + if (index >= BT_RFCOMM_SERVER_ID_MAX) + index = 0; + } + + latest_id = index; + id_used[index] = TRUE; + + BT_DBG("Assigned Id: %d", latest_id); + + return latest_id; +} + +void __rfcomm_delete_server_id(int id) +{ + ret_if(id >= BT_RFCOMM_SERVER_ID_MAX); + ret_if(id < 0); + + id_used[id] = FALSE; + + /* Next server will use this ID */ + latest_id = id - 1; +} + +static rfcomm_server_info_t *__get_rfcomm_server_info_with_uuid(const char *uuid) +{ + GSList *l; + + if (!uuid) + return NULL; + + for (l = rfcomm_servers; l != NULL; l = l->next) { + rfcomm_server_info_t *info = l->data; + + if (!strncasecmp(info->uuid, uuid, strlen(info->uuid))) + return info; + } + + return NULL; +} + +int _get_rfcomm_server_id(char *uuid, gboolean *auto_accept) +{ + rfcomm_server_info_t *server_info; + + server_info = __get_rfcomm_server_info_with_uuid(uuid); + if (!server_info) + return -1; + + *auto_accept = server_info->auto_accept; + return server_info->server_id; +} + +static rfcomm_server_info_t *__get_rfcomm_server_info_with_id(int server_id) +{ + GSList *l; + + for (l = rfcomm_servers; l != NULL; l = l->next) { + rfcomm_server_info_t *info = l->data; + if (!info) + continue; + + BT_DBG("info->server_fd: %d, sock_fd:%d", info->server_id, server_id); + if (info->server_id == server_id) + return info; + } + + return NULL; +} + +void _bt_rfcomm_server_set_pending_conn(int server_id, char *address) +{ + rfcomm_server_info_t *server_info; + + + if (!address) + return; + + server_info = __get_rfcomm_server_info_with_id(server_id); + if (!server_info) + return; + + g_strlcpy(server_info->pending_addr, address, BT_ADDRESS_STRING_SIZE); +} + +static rfcomm_remote_client_info_t *__get_rfcomm_rem_client_info_with_fd(int sock_fd) +{ + GSList *l; + GSList *l1; + + for (l = rfcomm_servers; l != NULL; l = l->next) { + rfcomm_server_info_t *info = l->data; + + if (!info) + continue; + + for (l1 = info->conn_list; l1 != NULL; l1 = l1->next) { + rfcomm_remote_client_info_t *client_info = l1->data; + if (!client_info) + continue; + + if (client_info->sock_fd == sock_fd) + return client_info; + } + } + + return NULL; +} + +static rfcomm_remote_client_info_t *__get_rfcomm_rem_client_info_with_addr(char *addr) +{ + GSList *l; + GSList *l1; + + retv_if(NULL == addr, NULL); + + for (l = rfcomm_servers; l != NULL; l = l->next) { + rfcomm_server_info_t *info = l->data; + + if (!info) + continue; + + for (l1 = info->conn_list; l1 != NULL; l1 = l1->next) { + rfcomm_remote_client_info_t *client_info = l1->data; + if (!client_info) + continue; + + if (!strncasecmp(client_info->addr, addr, strlen(client_info->addr))) + return client_info; + } + } + + return NULL; +} + +static void __remove_remote_client_info(rfcomm_remote_client_info_t *rem_client) +{ + BT_DBG("+"); + + if (rem_client == NULL) + return; + + if (0 < rem_client->sock_fd) { + shutdown(rem_client->sock_fd, SHUT_RDWR); + close(rem_client->sock_fd); + } + + if (rem_client->watch_id > 0) + g_source_remove(rem_client->watch_id); + + g_free(rem_client); + + BT_DBG("-"); +} + +static void __handle_rfcomm_client_disconnected(rfcomm_server_info_t *server_info, + rfcomm_remote_client_info_t *rem_client) +{ + bluetooth_rfcomm_disconnection_t disconn_info; + bt_event_info_t *event_info; + + BT_DBG("+"); + + if (rem_client == NULL || server_info == NULL) + return; + + event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT); + if (event_info == NULL) + return; + + memset(&disconn_info, 0x00, sizeof(bluetooth_rfcomm_disconnection_t)); + disconn_info.device_role = RFCOMM_ROLE_SERVER; + g_strlcpy(disconn_info.uuid, server_info->uuid, BLUETOOTH_UUID_STRING_MAX); + _bt_convert_addr_string_to_type(disconn_info.device_addr.addr, rem_client->addr); + BT_DBG("Disconnected FD [%d]", rem_client->sock_fd); + disconn_info.socket_fd = rem_client->sock_fd; + + _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DISCONNECTED, + BLUETOOTH_ERROR_NONE, &disconn_info, + event_info->cb, event_info->user_data); +} + +static void __remove_rfcomm_server(rfcomm_server_info_t *info) +{ + rfcomm_remote_client_info_t *client_info; + + BT_DBG("+"); + + if (!info) + return; + + rfcomm_servers = g_slist_remove(rfcomm_servers, info); + if (info->conn_list) { + do { + client_info = info->conn_list->data; + if (!client_info) + break; + + info->conn_list = g_slist_remove(info->conn_list, client_info); + __handle_rfcomm_client_disconnected(info, client_info); + __remove_remote_client_info(client_info); + } while (info->conn_list); + } + + if (info->server_fd) { + shutdown(info->server_fd, SHUT_RDWR); + close(info->server_fd); + } + + if (info->watch_id) + g_source_remove(info->watch_id); + + __rfcomm_delete_server_id(info->server_id); + g_free(info); + + BT_DBG("-"); +} + +static void __connected_cb(rfcomm_remote_client_info_t *client_info, bt_event_info_t *event_info) +{ + bluetooth_rfcomm_connection_t conn_info; + rfcomm_server_info_t *server_info; + + server_info = __get_rfcomm_server_info_with_id(client_info->server_id); + ret_if(server_info == NULL); + + memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t)); + conn_info.device_role = RFCOMM_ROLE_SERVER; + g_strlcpy(conn_info.uuid, server_info->uuid, BLUETOOTH_UUID_STRING_MAX); + conn_info.socket_fd = client_info->sock_fd; + _bt_convert_addr_string_to_type(conn_info.device_addr.addr, client_info->addr); + conn_info.server_id = server_info->server_id; + + 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 int __process_cmsg(struct msghdr *msg) +{ + int sock_fd = -1; + struct cmsghdr *cmsg_ptr = NULL; + + for (cmsg_ptr = CMSG_FIRSTHDR(msg); cmsg_ptr != NULL; + cmsg_ptr = CMSG_NXTHDR(msg, cmsg_ptr)) { + + if (cmsg_ptr->cmsg_level != SOL_SOCKET) + continue; + + if (cmsg_ptr->cmsg_type == SCM_RIGHTS) { + //int *desc = (int *)CMSG_DATA(cmsg_ptr); + int count + = ((cmsg_ptr->cmsg_len - CMSG_LEN(0)) / sizeof(int)); + + if (count < 0) { + BT_ERR("ERROR Invalid count of descriptors"); + continue; + } + + //sock_fd = desc[0]; + memcpy(&sock_fd, CMSG_DATA(cmsg_ptr), sizeof(sock_fd)); + BT_DBG("Remote client fd: %d", sock_fd); + } + } + + return sock_fd; +} + +static int __read_incomming_client_connection( + int server_fd, char *buf, unsigned int len, int *client_fd) +{ + int ret; + struct msghdr msg; + struct iovec iv; + struct cmsghdr cmsgbuf[2 * sizeof(struct cmsghdr) + 4]; + int retryCount = 0; + + retv_if(0 > server_fd, -1); + retv_if(NULL == client_fd, -1); + + BT_INFO("server_fd = %d", server_fd); + + memset(&msg, 0, sizeof(msg)); + memset(&iv, 0, sizeof(iv)); + + iv.iov_base = buf; + iv.iov_len = len; + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + for (retryCount = 0; retryCount < 5; retryCount++) { + ret = recvmsg(server_fd, &msg, 0); + BT_DBG("recvmsg ret = %d", ret); + if (ret < 0 && errno == EINTR) + continue; + else + break; + } + + if (ret < 0 && errno == EPIPE) { + /* End of stream, server listining stopped */ + BT_ERR("EOS errno: %d", errno); + return 0; + } + + if (ret < 0) { + BT_ERR("Ret errno: %d", errno); + return -1; + } + + if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) { + BT_ERR("MSG Flags errno: %d", errno); + return -1; + } + + BT_INFO("Connection received"); + *client_fd = __process_cmsg(&msg); + if (*client_fd < 0) + BT_ERR("Invalid client_fd received"); + + return ret; +} + +static gboolean __data_received_cb(GIOChannel *chan, GIOCondition cond, + gpointer data) +{ + char *buffer = NULL; + gsize len = 0; + int result = BLUETOOTH_ERROR_NONE; + bt_event_info_t *event_info; + bluetooth_rfcomm_received_data_t data_r; + GIOStatus status = G_IO_STATUS_NORMAL; + GError *err = NULL; + rfcomm_remote_client_info_t *client_info = data; + rfcomm_server_info_t *server_info; + + retv_if(client_info == NULL, FALSE); + + server_info = __get_rfcomm_server_info_with_id(client_info->server_id); + + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + BT_ERR_C("RFComm Server disconnected: %d", client_info->sock_fd); + goto fail; + } + + buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1); + status = g_io_channel_read_chars(chan, buffer, + BT_RFCOMM_BUFFER_LEN, &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); + goto fail; + } + g_error_free(err); + } + return TRUE; + } + + if (len == 0) { + BT_ERR("Length is zero, remote end hang up"); + goto fail; + } + + event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT); + if (event_info == NULL) { + g_free(buffer); + return TRUE; + } + + data_r.socket_fd = client_info->sock_fd; + data_r.buffer_size = len; + data_r.buffer = buffer; + + _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DATA_RECEIVED, + result, &data_r, + event_info->cb, event_info->user_data); + + g_free(buffer); + + return TRUE; + +fail: + BT_ERR("Failure occured, remove client connection"); + server_info->conn_list = g_slist_remove( + server_info->conn_list, client_info); + __handle_rfcomm_client_disconnected(server_info, client_info); + __remove_remote_client_info(client_info); + return FALSE; +} + +static gboolean __new_connection_request_cb(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + int len; + int size; + int channel; + int status; + int client_fd; + char buf[BLUETOOTH_SOCK_CONNECT_INFO_LEN]; + unsigned char addr[BT_ADDRESS_LENGTH_MAX]; + + bt_event_info_t *event_info; + GIOChannel *io; + rfcomm_remote_client_info_t *rem_client; + rfcomm_server_info_t *server_info = data; + + if (!server_info) { + BT_ERR("Server info is invalid"); + return FALSE; + } + + if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { + BT_INFO("RFCOMM Server with fd:%d is closed with cond:0x%X", + server_info->server_fd, cond); + goto err; + } + + BT_INFO("Server fd: %d", server_info->server_fd); + len = __read_incomming_client_connection( + server_info->server_fd, buf, BLUETOOTH_SOCK_CONNECT_INFO_LEN, &client_fd); + BT_DBG("Socket Read len: %d", len); + if (len == 0) { + BT_ERR("Listen stopped"); + goto err; + } else if (len != BLUETOOTH_SOCK_CONNECT_INFO_LEN) { + BT_ERR("Read length is not same as socket info length"); + goto err; + } + + len = 0; + /* Read size of data */ + size = buf[len] | (buf[len + 1] << 8); + len += 2; + + /* Read bluetooth address */ + memcpy(addr, buf + len, BT_ADDRESS_LENGTH_MAX); + len += BT_ADDRESS_LENGTH_MAX; + + /* Read channel */ + channel = buf[len] | (buf[len + 1] << 8) | + (buf[len + 2] << 16) | (buf[len + 3] << 24); + len += 4; + + /* Read status */ + status = buf[len] | (buf[len + 1] << 8) | + (buf[len + 2] << 16) | (buf[len + 3] << 24); + len += 4; + + BT_DBG("size: %d, channel: %d, status: %d", size, channel, status); + + rem_client = g_malloc0(sizeof(rfcomm_remote_client_info_t)); + rem_client->sock_fd = client_fd; + rem_client->server_id = server_info->server_id; + _bt_convert_addr_type_to_string(rem_client->addr, addr); + + BT_INFO("New client [%s] connection with socket_fd: %d, server_id: %d", + rem_client->addr, rem_client->sock_fd, rem_client->server_id); + + io = g_io_channel_unix_new(rem_client->sock_fd); + g_io_channel_set_encoding(io, NULL, NULL); + g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL); + rem_client->watch_id = g_io_add_watch(io, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + __data_received_cb, rem_client); + g_io_channel_unref(io); + + server_info->conn_list = g_slist_append(server_info->conn_list, rem_client); + event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT); + if (event_info) + __connected_cb(rem_client, event_info); + + return TRUE; + +err: + /* Error occurred, Remove RFCOMM server*/ + __remove_rfcomm_server(server_info); + return FALSE; +} + +static int __rfcomm_listen(rfcomm_server_info_t *server_info, bool accept) { int result; - int socket_fd = -1; - char uuid_str[BLUETOOTH_UUID_STRING_MAX]; + GUnixFDList *out_fd_list = NULL; + GIOChannel *server_io; - BT_CHECK_ENABLED(return); - BT_CHECK_PARAMETER(uuid, return); + retv_if(server_info == NULL, BLUETOOTH_ERROR_INTERNAL); BT_INIT_PARAMS(); BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); - g_strlcpy(uuid_str, uuid, sizeof(uuid_str)); - g_array_append_vals(in_param1, uuid_str, BLUETOOTH_UUID_STRING_MAX); - - result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_CREATE_SOCKET, - in_param1, in_param2, in_param3, in_param4, &out_param); + if (accept == false) { + g_array_append_vals(in_param1, server_info->uuid, BLUETOOTH_UUID_STRING_MAX); + result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_RFCOMM_LISTEN, + in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list); + } else { + g_array_append_vals(in_param1, server_info->uuid, BLUETOOTH_UUID_STRING_MAX); + result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_RFCOMM_LISTEN_AND_ACCEPT, + in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list); + } BT_DBG("result: %x", result); - - if (result == BLUETOOTH_ERROR_NONE) { - socket_fd = g_array_index(out_param, int, 0); - } else { + if (result != BLUETOOTH_ERROR_NONE) { BT_ERR("Fail to send request"); + return result; + } else if (NULL == out_fd_list) { + BT_ERR("out_fd_list is NULL"); + return BLUETOOTH_ERROR_INTERNAL; + } else { + int *fd_list_array; + int len = 0; + + if (!out_fd_list) + return BLUETOOTH_ERROR_INTERNAL; + + fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len); + BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]); + server_info->server_fd = fd_list_array[0]; + BT_INFO("Socket fd: %d", server_info->server_fd); + + g_free(fd_list_array); + g_object_unref(out_fd_list); } + server_io = g_io_channel_unix_new(server_info->server_fd); + g_io_channel_set_encoding(server_io, NULL, NULL); + g_io_channel_set_flags(server_io, G_IO_FLAG_NONBLOCK, NULL); + server_info->watch_id = g_io_add_watch(server_io, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + __new_connection_request_cb, server_info); + g_io_channel_unref(server_io); + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); - return socket_fd; + return BLUETOOTH_ERROR_NONE; } +#endif -BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int socket_fd) +BT_EXPORT_API int bluetooth_rfcomm_create_socket(const char *uuid) { - int result; +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; +#else + rfcomm_server_info_t *server_info; +#endif BT_CHECK_ENABLED(return); + BT_CHECK_PARAMETER(uuid, return); + BT_INFO("UUID Provided %s", uuid); - BT_INIT_PARAMS(); - BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_CREATE_SOCKET) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have a privilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; + } - g_array_append_vals(in_param1, &socket_fd, sizeof(int)); +#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 TIZEN_FEATURE_BT_RFCOMM_DIRECT + BT_INFO("<<<<<<<<< RFCOMM Create socket from app >>>>>>>>>"); + info = __register_method(); + if (info == NULL) + return -1; + + info->uuid = g_strdup(uuid); + info->disconnect_idle_id = 0; + return info->id; +#else + BT_INFO("<<<<<<<<< RFCOMM Create socket from app >>>>>>>>>"); + + server_info = __get_rfcomm_server_info_with_uuid(uuid); + if (!server_info) { + server_info = g_malloc0(sizeof(rfcomm_server_info_t)); + g_strlcpy(server_info->uuid, uuid, BLUETOOTH_UUID_STRING_MAX); + server_info->server_id = __rfcomm_assign_server_id(); + server_info->server_fd = -1; + server_info->watch_id = -1; + server_info->auto_accept = FALSE; + rfcomm_servers = g_slist_append(rfcomm_servers, server_info); + } + return server_info->server_id; +#endif +} - result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_REMOVE_SOCKET, - in_param1, in_param2, in_param3, in_param4, &out_param); +BT_EXPORT_API int bluetooth_rfcomm_create_socket_ex(const char *uuid, const char *bus_name, const char *path) +{ +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; - BT_DBG("result: %x", result); + BT_CHECK_ENABLED(return); + BT_CHECK_PARAMETER(path, return); + BT_INFO("PATH Provided %s", path); - if (result == BLUETOOTH_ERROR_NONE) { - _bt_remove_server(socket_fd); + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_CREATE_SOCKET_EX) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have a privilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; } - BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); +#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 Create socket from app >>>>>>>>>"); + info = __register_method_2(path, bus_name); + if (info == NULL) + return BLUETOOTH_ERROR_IN_PROGRESS; + info->uuid = g_strdup(uuid); + info->disconnect_idle_id = 0; + + return BLUETOOTH_ERROR_NONE; +#else + return BLUETOOTH_ERROR_NOT_SUPPORT; +#endif +} - return result; + +BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int id) +{ +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; +#else + rfcomm_server_info_t *server_info; +#endif + + BT_CHECK_ENABLED(return); + + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_REMOVE_SOCKET) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have a privilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; + } + + if (id < 0) { + BT_ERR("Invalid ID"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + BT_INFO("RFCOMM Remove socket request from app, ID [%d]", id); + + 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_profile(info->path); + + rfcomm_nodes = g_slist_remove(rfcomm_nodes, info); + free_rfcomm_info(info); + + return BLUETOOTH_ERROR_NONE; +#else + BT_INFO("<<<<<<<<< RFCOMM Remove socket request from app, fd=[%d] >>>>>>>>>>>", socket_fd); + + server_info = __get_rfcomm_server_info_with_id(id); + if (!server_info) { + BT_ERR("server_info not found for socket_fd: %d", id); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + __remove_rfcomm_server(server_info); + + return BLUETOOTH_ERROR_NONE; +#endif } -BT_EXPORT_API int bluetooth_rfcomm_server_disconnect(int socket_fd) +BT_EXPORT_API int bluetooth_rfcomm_remove_socket_ex(const char *uuid) { - int result; +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; BT_CHECK_ENABLED(return); - BT_INIT_PARAMS(); - BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_REMOVE_SOCKET) + == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have a privilege to use this API"); + return BLUETOOTH_ERROR_PERMISSION_DEINED; + } - g_array_append_vals(in_param1, &socket_fd, sizeof(int)); + BT_INFO("RFCOMM Remove socket request from app, uuid=[%s]", uuid); - result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_SOCKET_DISCONNECT, - in_param1, in_param2, in_param3, in_param4, &out_param); + info = __find_rfcomm_info_with_uuid(uuid); + if (info == NULL) + return BLUETOOTH_ERROR_INVALID_PARAM; - BT_DBG("result: %x", result); + _bt_unregister_osp_server_in_agent(BT_RFCOMM_SERVER, info->uuid); + _bt_unregister_profile(info->path); - BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + rfcomm_nodes = g_slist_remove(rfcomm_nodes, info); + free_rfcomm_info(info); - return result; + return BLUETOOTH_ERROR_NONE; +#else + return BLUETOOTH_ERROR_NOT_SUPPORT; +#endif +} + +BT_EXPORT_API int bluetooth_rfcomm_server_disconnect(int socket_fd) +{ +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; + rfcomm_conn_t *conn; + + char address[20]; + + BT_INFO(" ### Disconnect RFCOMM server"); + if (socket_fd < 0) { + BT_ERR("Invalid FD"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + info = __find_rfcomm_info_with_fd(socket_fd); + if (info == NULL) + return BLUETOOTH_ERROR_INVALID_PARAM; + + 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; + + close(conn->fd); + conn->disconnected = TRUE; + + _bt_convert_addr_type_to_string(address, conn->addr.addr); + + BT_DBG("Address %s", address); + _bt_disconnect_ext_profile(address, info->path); + + if (info->disconnect_idle_id == 0) + info->disconnect_idle_id = g_idle_add( + (GSourceFunc)__rfcomm_server_disconnect, info); + BT_DBG("-"); + + return BLUETOOTH_ERROR_NONE; +#else + rfcomm_remote_client_info_t *client_info; + + BT_CHECK_ENABLED(return); + + BT_INFO(">>>>>>>>RFCOMM server disconnect request from APP>>>>>>>>>"); + if (socket_fd < 0) { + BT_ERR("Invalid FD"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + client_info = __get_rfcomm_rem_client_info_with_fd(socket_fd); + if (!client_info) { + BT_ERR("client_info not found for socket_fd: %d", socket_fd); + return BLUETOOTH_ERROR_NOT_CONNECTED; + } + + if (client_info->sock_fd) { + shutdown(client_info->sock_fd, SHUT_RDWR); + close(client_info->sock_fd); + client_info->sock_fd = -1; + } + + return BLUETOOTH_ERROR_NONE; +#endif } BT_EXPORT_API gboolean bluetooth_rfcomm_is_server_uuid_available(const char *uuid) @@ -125,9 +1363,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); @@ -136,96 +1373,301 @@ BT_EXPORT_API gboolean bluetooth_rfcomm_is_server_uuid_available(const char *uui return available; } -BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int socket_fd, int max_pending_connection) +BT_EXPORT_API int bluetooth_rfcomm_server_is_connected(const bluetooth_device_address_t *device_address, gboolean *connected) { - int result; - gboolean native_service = TRUE; +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + GSList *l; + GSList *ll; + rfcomm_info_t *info; + rfcomm_conn_t *conn; +#else + char input_addr[BT_ADDRESS_STRING_SIZE] = { 0 }; + rfcomm_remote_client_info_t *info; +#endif + + BT_CHECK_PARAMETER(device_address, return); + BT_CHECK_PARAMETER(connected, return); + + *connected = FALSE; + +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + for (l = rfcomm_nodes; l; l = l->next) { + info = l->data; + + if (info == NULL || info->rfcomm_conns == NULL) + continue; + + 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; + } + } + + return BLUETOOTH_ERROR_NONE; +#else + _bt_convert_addr_type_to_string(input_addr, (unsigned char *)device_address->addr); + info = __get_rfcomm_rem_client_info_with_addr(input_addr); + if (info) + *connected = TRUE; + + return BLUETOOTH_ERROR_NONE; +#endif +} + +BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int id, int max_pending_connection) +{ +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; +#else + rfcomm_server_info_t *server_info; +#endif BT_CHECK_ENABLED(return); + if (id < 0) { + BT_ERR("Invalid ID"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } - BT_INIT_PARAMS(); - BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); +#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 - g_array_append_vals(in_param1, &socket_fd, sizeof(int)); - g_array_append_vals(in_param2, &max_pending_connection, sizeof(int)); - g_array_append_vals(in_param3, &native_service, sizeof(gboolean)); +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + BT_INFO("RFCOMM Listen & accept from app"); - result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_LISTEN, - in_param1, in_param2, in_param3, in_param4, &out_param); + info = __find_rfcomm_info_with_id(id); + if (info == NULL) + return BLUETOOTH_ERROR_INVALID_PARAM; - BT_DBG("result: %x", result); + bt_register_profile_info_t profile_info; + int result; - BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + profile_info.authentication = TRUE; + profile_info.authorization = TRUE; + profile_info.obj_path = info->path; + profile_info.role = NULL; + profile_info.service = info->uuid; + profile_info.uuid = info->uuid; + + BT_INFO("uuid %s", profile_info.uuid); + result = _bt_register_profile(&profile_info, TRUE); return result; +#else + BT_INFO("<<<<<<<<< RFCOMM Listen & accept from app >>>>>>>>>>>"); + + server_info = __get_rfcomm_server_info_with_id(id); + if (!server_info) { + BT_ERR("server_info not found for id: %d", id); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + if (server_info->server_fd >= 0) { + BT_ERR("server already listining"); + return BLUETOOTH_ERROR_DEVICE_BUSY; + } + + server_info->max_pending_conn = max_pending_connection; + server_info->auto_accept = TRUE; + + return __rfcomm_listen(server_info, true); +#endif } -BT_EXPORT_API int bluetooth_rfcomm_listen(int socket_fd, int max_pending_connection) +BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept_ex(const char *uuid, + int max_pending_connection, + const char *bus_name, const char *path) { - int result; - gboolean native_service = FALSE; +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; BT_CHECK_ENABLED(return); - BT_INIT_PARAMS(); - BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); +#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 - g_array_append_vals(in_param1, &socket_fd, sizeof(int)); - g_array_append_vals(in_param2, &max_pending_connection, sizeof(int)); - g_array_append_vals(in_param3, &native_service, sizeof(gboolean)); + BT_INFO("RFCOMM Listen & accept from app"); - result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_LISTEN, - in_param1, in_param2, in_param3, in_param4, &out_param); + info = __find_rfcomm_info_with_uuid(uuid); + if (info == NULL) + return BLUETOOTH_ERROR_INVALID_PARAM; - BT_DBG("result: %x", result); + bt_register_profile_info_t profile_info; + int result; - if (result == BLUETOOTH_ERROR_NONE) { - _bt_add_server(socket_fd); - } + profile_info.authentication = TRUE; + profile_info.authorization = TRUE; + profile_info.obj_path = info->path; + profile_info.role = NULL; + profile_info.service = info->uuid; + profile_info.uuid = info->uuid; - BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + BT_INFO("uuid %s", profile_info.uuid); + result = _bt_register_profile_ex(&profile_info, TRUE, bus_name, path); return result; +#else + return BLUETOOTH_ERROR_NOT_SUPPORT; +#endif } -BT_EXPORT_API int bluetooth_rfcomm_accept_connection(int server_fd, int *client_fd) +BT_EXPORT_API int bluetooth_rfcomm_listen(int id, int max_pending_connection) +{ +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT + rfcomm_info_t *info; +#else + rfcomm_server_info_t *server_info; +#endif + + BT_CHECK_ENABLED(return); + if (id < 0) { + BT_ERR("Invalid ID"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + +#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 TIZEN_FEATURE_BT_RFCOMM_DIRECT + BT_INFO("RFCOMM Listen"); + + info = __find_rfcomm_info_with_id(id); + if (info == NULL) + return BLUETOOTH_ERROR_INVALID_PARAM; + + bt_register_profile_info_t profile_info; + int result; + + profile_info.authentication = TRUE; + profile_info.authorization = TRUE; + profile_info.obj_path = info->path; + profile_info.role = NULL; + profile_info.service = info->uuid; + profile_info.uuid = info->uuid; + BT_INFO("UUID %s", info->uuid); + BT_INFO("PATH %s", info->path); + result = _bt_register_profile_platform(&profile_info, TRUE); + if (result != BLUETOOTH_ERROR_NONE) + return result; + + return _bt_register_osp_server_in_agent(BT_RFCOMM_SERVER, info->uuid, + info->path, id); + +#else + BT_INFO("<<<<<<<<< RFCOMM Listen >>>>>>>>>>>"); + + server_info = __get_rfcomm_server_info_with_id(id); + if (!server_info) { + BT_ERR("server_info not found for id: %d", id); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + if (server_info->server_fd >= 0) { + BT_ERR("server already listining"); + return BLUETOOTH_ERROR_DEVICE_BUSY; + } + + server_info->max_pending_conn = max_pending_connection; + server_info->auto_accept = FALSE; + return __rfcomm_listen(server_info, false); +#endif +} + +BT_EXPORT_API int bluetooth_rfcomm_accept_connection(int server_fd) { int result; +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT +#else + rfcomm_server_info_t *server_info; +#endif BT_CHECK_ENABLED(return); +#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 (server_fd < 0) { + BT_ERR("Invalid FD"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + BT_INIT_PARAMS(); BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT g_array_append_vals(in_param1, &server_fd, sizeof(int)); +#else + server_info = __get_rfcomm_server_info_with_id(server_fd); + if (!server_info) { + BT_ERR("No server with fd: %d", server_fd); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + g_array_append_vals(in_param1, server_info->pending_addr, BT_ADDRESS_STRING_SIZE); +#endif result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_ACCEPT_CONNECTION, in_param1, in_param2, in_param3, in_param4, &out_param); BT_DBG("result: %x", result); - if (result == BLUETOOTH_ERROR_NONE) { - *client_fd = g_array_index(out_param, int, 0); - } - BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); - BT_DBG("client_fd: %d", *client_fd); - return result; } BT_EXPORT_API int bluetooth_rfcomm_reject_connection(int server_fd) { int result; +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT +#else + rfcomm_server_info_t *server_info; +#endif BT_CHECK_ENABLED(return); + if (server_fd < 0) { + BT_ERR("Invalid FD"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + BT_INFO("+"); + BT_INIT_PARAMS(); BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); +#ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT g_array_append_vals(in_param1, &server_fd, sizeof(int)); +#else + server_info = __get_rfcomm_server_info_with_id(server_fd); + if (!server_info) { + BT_ERR("No server with fd: %d", server_fd); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + g_array_append_vals(in_param1, server_info->pending_addr, BT_ADDRESS_STRING_SIZE); +#endif result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_REJECT_CONNECTION, in_param1, in_param2, in_param3, in_param4, &out_param);