2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <sys/types.h>
19 #include <sys/socket.h>
23 #include <gio/gunixfdlist.h>
25 #include "bluetooth-api.h"
26 #include "bt-common.h"
27 #include "bt-internal-types.h"
28 #include "bt-request-sender.h"
30 #define HDP_BUFFER_SIZE 1024
31 #define BLUEZ_HDP_MANAGER_INTERFACE "org.bluez.HealthManager1"
32 #define BLUEZ_HDP_DEVICE_INTERFACE "org.bluez.HealthDevice1"
33 #define BLUEZ_HDP_CHANNEL_INTERFACE "org.bluez.HealthChannel1"
37 unsigned int channel_id;
47 static GSList *g_app_list = NULL;
49 /* Variable for privilege, only for write API,
50 * before we should reduce time to bt-service dbus calling
51 * -1 : Don't have a permission to access API
52 * 0 : Initial value, not yet check
53 * 1 : Have a permission to access API
55 static int privilege_token;
57 static void __bt_hdp_obj_info_free(hdp_obj_info_t *info)
63 g_source_remove(info->watch_id);
70 static hdp_app_list_t *__bt_hdp_internal_gslist_find_app_handler(void *app_handle)
74 retv_if(g_app_list == NULL, NULL);
76 BT_DBG("List length = %d\n", g_slist_length(g_app_list));
78 for (l = g_app_list; l != NULL; l = l->next) {
79 hdp_app_list_t *list = l->data;
82 if (0 == g_strcmp0((char *)list->app_handle,
91 static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_ch_id(unsigned int channel_id)
96 retv_if(g_app_list == NULL, NULL);
98 BT_DBG("List length = %d\n", g_slist_length(g_app_list));
100 for (l = g_app_list; l != NULL; l = l->next) {
101 hdp_app_list_t *list = l->data;
105 for (iter = list->obj_info; iter != NULL; iter = iter->next) {
106 hdp_obj_info_t *info = iter->data;
110 if (channel_id == info->channel_id)
118 static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_fd(unsigned int sock_fd)
123 retv_if(g_app_list == NULL, NULL);
125 BT_DBG("List length = %d\n", g_slist_length(g_app_list));
127 for (l = g_app_list; l != NULL; l = l->next) {
128 hdp_app_list_t *list = l->data;
132 for (iter = list->obj_info; iter != NULL; iter = iter->next) {
133 hdp_obj_info_t *info = iter->data;
137 if (sock_fd == info->fd)
145 static gboolean __bt_hdp_internal_data_received(GIOChannel *gio,
146 GIOCondition cond, gpointer data)
150 bt_user_info_t *user_info;
151 char buff[HDP_BUFFER_SIZE] = { 0, };
153 GIOStatus status = G_IO_STATUS_NORMAL;
154 bluetooth_device_address_t *address = data;
155 hdp_obj_info_t *info;
159 fd = g_io_channel_unix_get_fd(gio);
160 BT_DBG("fd: %d", fd);
162 info = __bt_hdp_internal_gslist_obj_find_using_fd(fd);
164 BT_INFO("No obj info found for fd: %d", fd);
169 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
170 bt_hdp_disconnected_t disconn_info;
171 bt_user_info_t *user_info;
172 hdp_app_list_t *list;
174 BT_DBG("GIOCondition %d", cond);
175 disconn_info.channel_id = info->channel_id;
176 memcpy(&disconn_info.device_address, address, sizeof(bluetooth_device_address_t));
178 list = __bt_hdp_internal_gslist_find_app_handler(info->app_handle);
180 list->obj_info = g_slist_remove(list->obj_info, info);
181 __bt_hdp_obj_info_free(info);
184 user_info = _bt_get_user_data(BT_COMMON);
185 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DISCONNECTED,
186 BLUETOOTH_ERROR_NONE, &disconn_info,
187 user_info->cb, user_info->user_data);
192 status = g_io_channel_read_chars(gio, buff, HDP_BUFFER_SIZE, &len, &err);
193 if (status != G_IO_STATUS_NORMAL) {
194 BT_ERR("IO Channel read is failed with %d", status);
196 BT_ERR("IO Channel read error [%s]", err->message);
203 BT_DBG("fd: %d, len: %d, buffer: %s", fd, len, buff);
205 user_info = _bt_get_user_data(BT_COMMON);
207 bt_hdp_data_ind_t data_ind = { 0, };
209 data_ind.channel_id = info->channel_id;
210 data_ind.buffer = buff;
212 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DATA_RECEIVED,
213 BLUETOOTH_ERROR_NONE, &data_ind,
214 user_info->cb, user_info->user_data);
221 static void __hdp_handle_new_connection(bt_hdp_connected_t *conn_info, int fd)
223 hdp_obj_info_t *info;
224 hdp_app_list_t *list;
225 bluetooth_device_address_t *address;
230 list = __bt_hdp_internal_gslist_find_app_handler((void *)conn_info->app_handle);
232 BT_ERR("**** Could not locate the list for %s*****\n", conn_info->app_handle);
236 info = g_new0(hdp_obj_info_t, 1);
237 info->channel_id = conn_info->channel_id;
238 info->app_handle = list->app_handle;
240 address = g_memdup(&(conn_info->device_address), sizeof(bluetooth_device_address_t));
242 gio = g_io_channel_unix_new(fd);
243 g_io_channel_set_close_on_unref(gio, TRUE);
244 info->watch_id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
245 __bt_hdp_internal_data_received, (void *)address);
246 g_io_channel_unref(gio);
247 list->obj_info = g_slist_append(list->obj_info, info);
252 void _bt_hdp_app_remove_obj_info(unsigned int channel_id)
254 hdp_app_list_t *list;
255 hdp_obj_info_t *info;
259 info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
260 ret_if(NULL == info);
262 list = __bt_hdp_internal_gslist_find_app_handler(info->app_handle);
263 ret_if(NULL == list);
265 list->obj_info = g_slist_remove(list->obj_info, info);
266 BT_DBG("obj_info length = %d\n", g_slist_length(list->obj_info));
267 __bt_hdp_obj_info_free(info);
272 int _bt_hdp_app_acquire_fd(bt_hdp_connected_t *conn_info)
275 GUnixFDList *out_fd_list = NULL;
278 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
280 g_array_append_vals(in_param1, &conn_info->channel_id, sizeof(int));
281 result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_HDP_GET_FD,
282 in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list);
284 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
286 BT_DBG("result: %x", result);
287 if (result != BLUETOOTH_ERROR_NONE || NULL == out_fd_list) {
288 BT_ERR("out_fd_list is NULL");
289 bluetooth_hdp_disconnect(conn_info->channel_id, &conn_info->device_address);
290 return BLUETOOTH_ERROR_INTERNAL;
295 fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len);
296 BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]);
297 __hdp_handle_new_connection(conn_info, fd_list_array[0]);
298 g_free(fd_list_array);
299 g_object_unref(out_fd_list);
303 return BLUETOOTH_ERROR_NONE;
306 /**********************************************************************
307 * Health device APIs (HDP) *
308 ***********************************************************************/
309 BT_EXPORT_API int bluetooth_hdp_activate(unsigned short data_type,
310 bt_hdp_role_type_t role,
311 bt_hdp_qos_type_t channel_type,
314 int result = BLUETOOTH_ERROR_NONE;
318 BT_CHECK_ENABLED(return);
320 /*For source role is mandatory */
321 if (role == HDP_ROLE_SOURCE && channel_type == HDP_QOS_ANY) {
322 BT_ERR("For source, type is mandatory - Reliable/Streaming");
323 return BLUETOOTH_ERROR_INVALID_PARAM;
327 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
329 g_array_append_vals(in_param1, &data_type, sizeof(short));
330 g_array_append_vals(in_param2, &role, sizeof(bt_hdp_role_type_t));
331 g_array_append_vals(in_param3, &channel_type, sizeof(bt_hdp_qos_type_t));
333 result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_CREATE_APPLICATION,
334 in_param1, in_param2, in_param3, in_param4, &out_param);
336 if (result == BLUETOOTH_ERROR_NONE) {
338 hdp_app_list_t *list;
340 buf = &g_array_index(out_param, char, 0);
341 BT_DBG("Created app: %s", buf);
343 list = g_new0(hdp_app_list_t, 1);
344 list->app_handle = (void *)g_strdup(buf);
345 *app_handle = list->app_handle;
346 g_app_list = g_slist_append(g_app_list, list);
349 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
355 BT_EXPORT_API int bluetooth_hdp_deactivate(const char *app_handle)
358 hdp_app_list_t *list;
362 BT_CHECK_ENABLED(return);
363 BT_CHECK_PARAMETER(app_handle, return);
365 list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
367 BT_ERR("**** list not found for %s ******\n", app_handle);
368 return BLUETOOTH_ERROR_INVALID_PARAM;
371 BT_DBG("app_handle: %s", app_handle);
374 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
376 g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
378 result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_DESTROY_APPLICATION,
379 in_param1, in_param2, in_param3, in_param4, &out_param);
380 if (result == BLUETOOTH_ERROR_NONE) {
381 g_app_list = g_slist_remove(g_app_list, list);
382 g_free(list->app_handle);
383 g_slist_foreach(list->obj_info, (GFunc)__bt_hdp_obj_info_free, NULL);
387 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
392 BT_EXPORT_API int bluetooth_hdp_send_data(unsigned int channel_id,
398 hdp_obj_info_t *info;
403 BT_CHECK_ENABLED(return);
405 retv_if (NULL == buffer, BLUETOOTH_ERROR_INVALID_PARAM);
406 retv_if (0 == size, BLUETOOTH_ERROR_INVALID_PARAM);
408 info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
410 BT_ERR("*** Could not locate the info for %d*****", channel_id);
411 return BLUETOOTH_ERROR_INVALID_PARAM;
414 switch (privilege_token) {
416 result = _bt_check_privilege(BT_BLUEZ_SERVICE, BT_HDP_SEND_DATA);
418 if (result == BLUETOOTH_ERROR_NONE) {
419 privilege_token = 1; /* Have a permission */
420 } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
421 BT_ERR("Don't have a privilege to use this API");
422 privilege_token = -1; /* Don't have a permission */
423 return BLUETOOTH_ERROR_PERMISSION_DEINED;
425 /* Just break - It is not related with permission error */
429 /* Already have a privilege */
432 return BLUETOOTH_ERROR_PERMISSION_DEINED;
434 /* Invalid privilge token value */
435 return BLUETOOTH_ERROR_INTERNAL;
438 while (wbytes < size) {
439 written = write(info->fd, (buffer + wbytes), (size - wbytes));
441 BT_ERR("write failed..\n");
442 return BLUETOOTH_ERROR_NOT_IN_OPERATION;
447 return BLUETOOTH_ERROR_NONE;
450 BT_EXPORT_API int bluetooth_hdp_connect(const char *app_handle,
451 bt_hdp_qos_type_t channel_type,
452 const bluetooth_device_address_t *device_address)
455 hdp_app_list_t *list;
456 bt_user_info_t *user_info;
458 BT_CHECK_ENABLED(return);
459 BT_CHECK_PARAMETER(app_handle, return);
460 BT_CHECK_PARAMETER(device_address, return);
462 user_info = _bt_get_user_data(BT_COMMON);
463 retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
465 list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
467 BT_ERR("**** list not found for %s ******\n", app_handle);
468 return BLUETOOTH_ERROR_INVALID_PARAM;
471 BT_DBG("app_handle: %s", app_handle);
474 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
476 g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
477 g_array_append_vals(in_param2, &channel_type, sizeof(bt_hdp_qos_type_t));
478 g_array_append_vals(in_param3, device_address, sizeof(bluetooth_device_address_t));
480 result = _bt_send_request_async(BT_BLUEZ_SERVICE,
481 BT_HDP_CONNECT, in_param1, in_param2, in_param3, in_param4,
482 user_info->cb, user_info->user_data);
484 if (result != BLUETOOTH_ERROR_NONE)
485 BT_ERR("BT_HDP_CONNECT failed");
487 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
492 BT_EXPORT_API int bluetooth_hdp_disconnect(unsigned int channel_id,
493 const bluetooth_device_address_t *device_address)
496 hdp_obj_info_t *info;
497 bt_user_info_t *user_info;
499 BT_CHECK_ENABLED(return);
500 BT_CHECK_PARAMETER(device_address, return);
502 user_info = _bt_get_user_data(BT_COMMON);
503 retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
505 BT_DBG("channel_id: %d", channel_id);
506 info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
508 BT_ERR("*** Could not locate the info for %d*****", channel_id);
509 return BLUETOOTH_ERROR_INVALID_PARAM;
513 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
515 g_array_append_vals(in_param1, &channel_id, sizeof(int));
516 g_array_append_vals(in_param2, device_address, sizeof(bluetooth_device_address_t));
518 result = _bt_send_request_async(BT_BLUEZ_SERVICE, BT_HDP_DISCONNECT,
519 in_param1, in_param2, in_param3, in_param4,
520 user_info->cb, user_info->user_data);
521 if (result != BLUETOOTH_ERROR_NONE)
522 BT_ERR("BT_HDP_DISCONNECT failed");
524 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);