#include "bluetooth-api.h"
#include "bt-common.h"
#include "bt-internal-types.h"
+#include "bt-request-sender.h"
-/**********************************************************************
-* Static Functions declaration *
-***********************************************************************/
+#define HDP_BUFFER_SIZE 1024
+#define BLUEZ_HDP_MANAGER_INTERFACE "org.bluez.HealthManager1"
+#define BLUEZ_HDP_DEVICE_INTERFACE "org.bluez.HealthDevice1"
+#define BLUEZ_HDP_CHANNEL_INTERFACE "org.bluez.HealthChannel1"
+
+typedef struct {
+ int fd;
+ unsigned int channel_id;
+ guint watch_id;
+ void *app_handle;
+} hdp_obj_info_t;
+
+typedef struct {
+ void *app_handle;
+ GSList *obj_info;
+} hdp_app_list_t;
+
+static GSList *g_app_list = NULL;
+
+/* Variable for privilege, only for write API,
+ * before we should reduce time to bt-service dbus calling
+ * -1 : Don't have a permission to access API
+ * 0 : Initial value, not yet check
+ * 1 : Have a permission to access API
+ */
+static int privilege_token;
+
+static void __bt_hdp_obj_info_free(hdp_obj_info_t *info)
+{
+ if (info) {
+ g_source_remove(info->watch_id);
+ close(info->fd);
+ g_free(info);
+ }
+}
+
+static hdp_app_list_t *__bt_hdp_internal_gslist_find_app_handler(void *app_handle)
+{
+ GSList *l;
+
+ retv_if(g_app_list == NULL, NULL);
+
+ BT_DBG("List length = %d\n", g_slist_length(g_app_list));
+
+ for (l = g_app_list; l != NULL; l = l->next) {
+ hdp_app_list_t *list = l->data;
+
+ if (list) {
+ if (0 == g_strcmp0((char *)list->app_handle,
+ (char *)app_handle))
+ return list;
+ }
+ }
+
+ return NULL;
+}
+
+static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_ch_id(unsigned int channel_id)
+{
+ GSList *l;
+ GSList *iter;
+
+ retv_if(g_app_list == NULL, NULL);
+
+ BT_DBG("List length = %d\n", g_slist_length(g_app_list));
+
+ for (l = g_app_list; l != NULL; l = l->next) {
+ hdp_app_list_t *list = l->data;
+ if (!list)
+ return NULL;
+
+ for (iter = list->obj_info; iter != NULL; iter = iter->next) {
+ hdp_obj_info_t *info = iter->data;
+ if (!info)
+ return NULL;
+
+ if (channel_id == info->channel_id)
+ return info;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean __bt_hdp_internal_data_received(GIOChannel *gio,
+ GIOCondition cond, gpointer data)
+{
+ int fd;
+ gsize len = 0;
+ bt_user_info_t *user_info;
+ char buff[HDP_BUFFER_SIZE] = { 0, };
+ GError *err = NULL;
+ GIOStatus status = G_IO_STATUS_NORMAL;
+ hdp_obj_info_t *info = data;
+
+ BT_DBG("+");
+
+ retv_if(NULL == info, FALSE);
+
+ fd = g_io_channel_unix_get_fd(gio);
+ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+ BT_DBG("GIOCondition %d", cond);
+ g_io_channel_shutdown(gio, TRUE, NULL);
+ g_io_channel_unref(gio);
+ _bt_hdp_app_remove_obj_info(info->channel_id);
+ /* TODO: call hdp_disconnect and send disconnect event if needed */
+ return FALSE;
+ }
+
+ status = g_io_channel_read_chars(gio, buff, HDP_BUFFER_SIZE, &len, &err);
+ if (status != G_IO_STATUS_NORMAL) {
+ BT_ERR("IO Channel read is failed with %d", status);
+ if (err) {
+ BT_ERR("IO Channel read error [%s]", err->message);
+ g_error_free(err);
+ }
+ return FALSE;
+ }
+
+ BT_DBG("fd: %d, len: %d, buffer: %s", fd, len, buff);
+
+ user_info = _bt_get_user_data(BT_COMMON);
+ if (user_info->cb) {
+ bt_hdp_data_ind_t data_ind = { 0, };
+
+ data_ind.channel_id = info->channel_id;
+ data_ind.buffer = buff;
+ data_ind.size = len;
+ _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DATA_RECEIVED,
+ BLUETOOTH_ERROR_NONE, &data_ind,
+ user_info->cb, user_info->user_data);
+ }
+
+ BT_DBG("-");
+ return TRUE;
+}
+
+static void __hdp_handle_new_connection(bt_hdp_connected_t *conn_info, int fd)
+{
+ hdp_obj_info_t *info;
+ hdp_app_list_t *list;
+ GIOChannel *gio;
+
+ BT_DBG("+");
+
+ list = __bt_hdp_internal_gslist_find_app_handler((void *)conn_info->app_handle);
+ if (NULL == list) {
+ BT_ERR("**** Could not locate the list for %s*****\n", conn_info->app_handle);
+ return;
+ }
+
+ info = g_new0(hdp_obj_info_t, 1);
+ info->channel_id = conn_info->channel_id;
+ info->app_handle = list->app_handle;
+ info->fd = fd;
+
+ gio = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(gio, TRUE);
+ info->watch_id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ __bt_hdp_internal_data_received, (void *)info);
+ g_io_channel_unref(gio);
+ list->obj_info = g_slist_append(list->obj_info, info);
+
+ BT_DBG("-");
+}
+
+void _bt_hdp_app_remove_obj_info(unsigned int channel_id)
+{
+ hdp_app_list_t *list;
+ hdp_obj_info_t *info;
+
+ BT_DBG("+");
+
+ info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
+ ret_if(NULL == info);
+
+ list = __bt_hdp_internal_gslist_find_app_handler(info->app_handle);
+ ret_if(NULL == list);
+
+ list->obj_info = g_slist_remove(list->obj_info, info);
+ __bt_hdp_obj_info_free(info);
+
+ BT_DBG("-");
+}
+
+int _bt_hdp_app_acquire_fd(bt_hdp_connected_t *conn_info)
+{
+ int result;
+ GUnixFDList *out_fd_list = NULL;
+
+ BT_INIT_PARAMS();
+ BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ g_array_append_vals(in_param1, &conn_info->channel_id, sizeof(int));
+ result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_HDP_GET_FD,
+ in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list);
+
+ BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ BT_DBG("result: %x", result);
+ if (result != BLUETOOTH_ERROR_NONE || NULL == out_fd_list) {
+ BT_ERR("out_fd_list is NULL");
+ bluetooth_hdp_disconnect(conn_info->channel_id, &conn_info->device_address);
+ return BLUETOOTH_ERROR_INTERNAL;
+ } else {
+ int *fd_list_array;
+ int len = 0;
+
+ 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]);
+ __hdp_handle_new_connection(conn_info, fd_list_array[0]);
+ g_free(fd_list_array);
+ g_object_unref(out_fd_list);
+ }
+
+ BT_DBG("-");
+ return BLUETOOTH_ERROR_NONE;
+}
/**********************************************************************
* Health device APIs (HDP) *
***********************************************************************/
-
BT_EXPORT_API int bluetooth_hdp_activate(unsigned short data_type,
bt_hdp_role_type_t role,
bt_hdp_qos_type_t channel_type,
char **app_handle)
{
- return BLUETOOTH_ERROR_NONE;
+ int result = BLUETOOTH_ERROR_NONE;
+
+ BT_DBG("+");
+
+ BT_CHECK_ENABLED(return);
+
+ /*For source role is mandatory */
+ if (role == HDP_ROLE_SOURCE && channel_type == HDP_QOS_ANY) {
+ BT_ERR("For source, type is mandatory - Reliable/Streaming");
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+ }
+
+ BT_INIT_PARAMS();
+ BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ g_array_append_vals(in_param1, &data_type, sizeof(short));
+ g_array_append_vals(in_param2, &role, sizeof(bt_hdp_role_type_t));
+ g_array_append_vals(in_param3, &channel_type, sizeof(bt_hdp_qos_type_t));
+
+ result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_CREATE_APPLICATION,
+ in_param1, in_param2, in_param3, in_param4, &out_param);
+
+ if (result == BLUETOOTH_ERROR_NONE) {
+ char *buf;
+ hdp_app_list_t *list;
+
+ buf = &g_array_index(out_param, char, 0);
+ BT_DBG("Created app: %s", buf);
+
+ list = g_new0(hdp_app_list_t, 1);
+ list->app_handle = (void *)g_strdup(buf);
+ *app_handle = list->app_handle;
+ g_app_list = g_slist_append(g_app_list, list);
+ }
+
+ BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ BT_DBG("-");
+ return result;
}
BT_EXPORT_API int bluetooth_hdp_deactivate(const char *app_handle)
{
- return BLUETOOTH_ERROR_NONE;
+ int result;
+ hdp_app_list_t *list;
+
+ BT_DBG("+");
+
+ BT_CHECK_ENABLED(return);
+ BT_CHECK_PARAMETER(app_handle, return);
+
+ list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
+ if (NULL == list) {
+ BT_ERR("**** list not found for %s ******\n", app_handle);
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+ }
+
+ BT_DBG("app_handle: %s", app_handle);
+
+ BT_INIT_PARAMS();
+ BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
+
+ result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_DESTROY_APPLICATION,
+ in_param1, in_param2, in_param3, in_param4, &out_param);
+ if (result == BLUETOOTH_ERROR_NONE) {
+ g_app_list = g_slist_remove(g_app_list, list);
+ g_free(list->app_handle);
+ g_slist_foreach(list->obj_info, (GFunc)__bt_hdp_obj_info_free, NULL);
+ g_free(list);
+ }
+
+ BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ return result;
}
BT_EXPORT_API int bluetooth_hdp_send_data(unsigned int channel_id,
const char *buffer,
unsigned int size)
{
+ int wbytes = 0;
+ int written = 0;
+ hdp_obj_info_t *info;
+ int result;
+
+ BT_DBG("+");
+
+ BT_CHECK_ENABLED(return);
+
+ retv_if (NULL == buffer, BLUETOOTH_ERROR_INVALID_PARAM);
+ retv_if (0 == size, BLUETOOTH_ERROR_INVALID_PARAM);
+
+ info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
+ if (NULL == info) {
+ BT_ERR("*** Could not locate the info for %d*****", channel_id);
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+ }
+
+ switch (privilege_token) {
+ case 0:
+ result = _bt_check_privilege(BT_BLUEZ_SERVICE, BT_HDP_SEND_DATA);
+
+ if (result == BLUETOOTH_ERROR_NONE) {
+ privilege_token = 1; /* Have a permission */
+ } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
+ BT_ERR("Don't have a privilege to use this API");
+ privilege_token = -1; /* Don't have a permission */
+ return BLUETOOTH_ERROR_PERMISSION_DEINED;
+ } else {
+ /* Just break - It is not related with permission error */
+ }
+ break;
+ case 1:
+ /* Already have a privilege */
+ break;
+ case -1:
+ return BLUETOOTH_ERROR_PERMISSION_DEINED;
+ default:
+ /* Invalid privilge token value */
+ return BLUETOOTH_ERROR_INTERNAL;
+ }
+
+ while (wbytes < size) {
+ written = write(info->fd, (buffer + wbytes), (size - wbytes));
+ if (written <= 0) {
+ BT_ERR("write failed..\n");
+ return BLUETOOTH_ERROR_NOT_IN_OPERATION;
+ }
+ wbytes += written;
+ }
+
return BLUETOOTH_ERROR_NONE;
}
bt_hdp_qos_type_t channel_type,
const bluetooth_device_address_t *device_address)
{
- return BLUETOOTH_ERROR_NONE;
+ int result;
+ hdp_app_list_t *list;
+ bt_user_info_t *user_info;
+
+ BT_CHECK_ENABLED(return);
+ BT_CHECK_PARAMETER(app_handle, return);
+ BT_CHECK_PARAMETER(device_address, return);
+
+ user_info = _bt_get_user_data(BT_COMMON);
+ retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
+
+ list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
+ if (NULL == list) {
+ BT_ERR("**** list not found for %s ******\n", app_handle);
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+ }
+
+ BT_DBG("app_handle: %s", app_handle);
+
+ BT_INIT_PARAMS();
+ BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
+ g_array_append_vals(in_param2, &channel_type, sizeof(bt_hdp_qos_type_t));
+ g_array_append_vals(in_param3, device_address, sizeof(bluetooth_device_address_t));
+
+ result = _bt_send_request_async(BT_BLUEZ_SERVICE,
+ BT_HDP_CONNECT, in_param1, in_param2, in_param3, in_param4,
+ user_info->cb, user_info->user_data);
+
+ if (result != BLUETOOTH_ERROR_NONE)
+ BT_ERR("BT_HDP_CONNECT failed");
+
+ BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ return result;
}
BT_EXPORT_API int bluetooth_hdp_disconnect(unsigned int channel_id,
const bluetooth_device_address_t *device_address)
{
- return BLUETOOTH_ERROR_NONE;
+ int result;
+ hdp_obj_info_t *info;
+ bt_user_info_t *user_info;
+
+ BT_CHECK_ENABLED(return);
+ BT_CHECK_PARAMETER(device_address, return);
+
+ user_info = _bt_get_user_data(BT_COMMON);
+ retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
+
+ BT_DBG("channel_id: %d", channel_id);
+ info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
+ if (NULL == info) {
+ BT_ERR("*** Could not locate the info for %d*****", channel_id);
+ return BLUETOOTH_ERROR_INVALID_PARAM;
+ }
+
+ BT_INIT_PARAMS();
+ BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+
+ g_array_append_vals(in_param1, &channel_id, sizeof(int));
+ g_array_append_vals(in_param2, device_address, sizeof(bluetooth_device_address_t));
+
+ result = _bt_send_request_async(BT_BLUEZ_SERVICE, BT_HDP_DISCONNECT,
+ in_param1, in_param2, in_param3, in_param4,
+ user_info->cb, user_info->user_data);
+ if (result != BLUETOOTH_ERROR_NONE)
+ BT_ERR("BT_HDP_DISCONNECT failed");
+
+ BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
+ return result;
}