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 ((int)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 hdp_app_list_t *list;
173 BT_DBG("GIOCondition %d", cond);
174 disconn_info.channel_id = info->channel_id;
175 memcpy(&disconn_info.device_address, address, sizeof(bluetooth_device_address_t));
177 list = __bt_hdp_internal_gslist_find_app_handler(info->app_handle);
179 list->obj_info = g_slist_remove(list->obj_info, info);
180 __bt_hdp_obj_info_free(info);
183 user_info = _bt_get_user_data(BT_COMMON);
184 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DISCONNECTED,
185 BLUETOOTH_ERROR_NONE, &disconn_info,
186 user_info->cb, user_info->user_data);
191 status = g_io_channel_read_chars(gio, buff, HDP_BUFFER_SIZE, &len, &err);
192 if (status != G_IO_STATUS_NORMAL) {
193 BT_ERR("IO Channel read is failed with %d", status);
195 BT_ERR("IO Channel read error [%s]", err->message);
202 BT_DBG("fd: %d, len: %zd, buffer: %s", fd, len, buff);
204 user_info = _bt_get_user_data(BT_COMMON);
206 bt_hdp_data_ind_t data_ind = { 0, };
208 data_ind.channel_id = info->channel_id;
209 data_ind.buffer = buff;
211 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DATA_RECEIVED,
212 BLUETOOTH_ERROR_NONE, &data_ind,
213 user_info->cb, user_info->user_data);
220 static void __hdp_handle_new_connection(bt_hdp_connected_t *conn_info, int fd)
222 hdp_obj_info_t *info;
223 hdp_app_list_t *list;
224 bluetooth_device_address_t *address;
229 list = __bt_hdp_internal_gslist_find_app_handler((void *)conn_info->app_handle);
231 BT_ERR("**** Could not locate the list for %s*****\n", conn_info->app_handle);
235 info = g_new0(hdp_obj_info_t, 1);
236 info->channel_id = conn_info->channel_id;
237 info->app_handle = list->app_handle;
239 address = g_memdup(&(conn_info->device_address), sizeof(bluetooth_device_address_t));
241 gio = g_io_channel_unix_new(fd);
242 g_io_channel_set_close_on_unref(gio, TRUE);
243 info->watch_id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
244 __bt_hdp_internal_data_received, (void *)address);
245 g_io_channel_unref(gio);
246 list->obj_info = g_slist_append(list->obj_info, info);
251 void _bt_hdp_app_remove_obj_info(unsigned int channel_id)
253 hdp_app_list_t *list;
254 hdp_obj_info_t *info;
258 info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
259 ret_if(NULL == info);
261 list = __bt_hdp_internal_gslist_find_app_handler(info->app_handle);
262 ret_if(NULL == list);
264 list->obj_info = g_slist_remove(list->obj_info, info);
265 BT_DBG("obj_info length = %d\n", g_slist_length(list->obj_info));
266 __bt_hdp_obj_info_free(info);
271 int _bt_hdp_app_acquire_fd(bt_hdp_connected_t *conn_info)
274 GUnixFDList *out_fd_list = NULL;
277 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
279 g_array_append_vals(in_param1, &conn_info->channel_id, sizeof(int));
280 result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_HDP_GET_FD,
281 in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list);
283 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
285 BT_DBG("result: %x", result);
286 if (result != BLUETOOTH_ERROR_NONE || NULL == out_fd_list) {
287 BT_ERR("out_fd_list is NULL");
288 bluetooth_hdp_disconnect(conn_info->channel_id, &conn_info->device_address);
289 return BLUETOOTH_ERROR_INTERNAL;
294 fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len);
295 BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]);
296 __hdp_handle_new_connection(conn_info, fd_list_array[0]);
297 g_free(fd_list_array);
298 g_object_unref(out_fd_list);
302 return BLUETOOTH_ERROR_NONE;
305 /**********************************************************************
306 * Health device APIs (HDP) *
307 ***********************************************************************/
308 BT_EXPORT_API int bluetooth_hdp_activate(unsigned short data_type,
309 bt_hdp_role_type_t role,
310 bt_hdp_qos_type_t channel_type,
313 int result = BLUETOOTH_ERROR_NONE;
317 BT_CHECK_ENABLED(return);
319 /*For source role is mandatory */
320 if (role == HDP_ROLE_SOURCE && channel_type == HDP_QOS_ANY) {
321 BT_ERR("For source, type is mandatory - Reliable/Streaming");
322 return BLUETOOTH_ERROR_INVALID_PARAM;
326 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
328 g_array_append_vals(in_param1, &data_type, sizeof(short));
329 g_array_append_vals(in_param2, &role, sizeof(bt_hdp_role_type_t));
330 g_array_append_vals(in_param3, &channel_type, sizeof(bt_hdp_qos_type_t));
332 result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_REGISTER_SINK_APP,
333 in_param1, in_param2, in_param3, in_param4, &out_param);
335 if (result == BLUETOOTH_ERROR_NONE) {
337 hdp_app_list_t *list;
339 buf = &g_array_index(out_param, char, 0);
340 BT_DBG("Created app: %s", buf);
342 list = g_new0(hdp_app_list_t, 1);
343 list->app_handle = (void *)g_strdup(buf);
344 *app_handle = list->app_handle;
345 g_app_list = g_slist_append(g_app_list, list);
348 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
354 BT_EXPORT_API int bluetooth_hdp_deactivate(const char *app_handle)
357 hdp_app_list_t *list;
361 BT_CHECK_ENABLED(return);
362 BT_CHECK_PARAMETER(app_handle, return);
364 list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
366 BT_ERR("**** list not found for %s ******\n", app_handle);
367 return BLUETOOTH_ERROR_INVALID_PARAM;
370 BT_DBG("app_handle: %s", app_handle);
373 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
375 g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
377 result = _bt_send_request(BT_BLUEZ_SERVICE, BT_HDP_UNREGISTER_SINK_APP,
378 in_param1, in_param2, in_param3, in_param4, &out_param);
379 if (result == BLUETOOTH_ERROR_NONE) {
380 g_app_list = g_slist_remove(g_app_list, list);
381 g_free(list->app_handle);
382 g_slist_foreach(list->obj_info, (GFunc)__bt_hdp_obj_info_free, NULL);
386 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
391 BT_EXPORT_API int bluetooth_hdp_send_data(unsigned int channel_id,
395 unsigned int wbytes = 0;
397 hdp_obj_info_t *info;
402 BT_CHECK_ENABLED(return);
404 retv_if(NULL == buffer, BLUETOOTH_ERROR_INVALID_PARAM);
405 retv_if(0 == size, BLUETOOTH_ERROR_INVALID_PARAM);
407 info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
409 BT_ERR("*** Could not locate the info for %d*****", channel_id);
410 return BLUETOOTH_ERROR_INVALID_PARAM;
413 switch (privilege_token) {
415 result = _bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HDP_SEND_DATA);
417 if (result == BLUETOOTH_ERROR_NONE) {
418 privilege_token = 1; /* Have a permission */
419 } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
420 BT_ERR("Don't have a privilege to use this API");
421 privilege_token = -1; /* Don't have a permission */
422 return BLUETOOTH_ERROR_PERMISSION_DEINED;
424 /* Just break - It is not related with permission error */
428 /* Already have a privilege */
431 return BLUETOOTH_ERROR_PERMISSION_DEINED;
433 /* Invalid privilge token value */
434 return BLUETOOTH_ERROR_INTERNAL;
437 while (wbytes < size) {
438 written = write(info->fd, (buffer + wbytes), (size - wbytes));
440 BT_ERR("write failed..\n");
441 return BLUETOOTH_ERROR_NOT_IN_OPERATION;
446 return BLUETOOTH_ERROR_NONE;
449 BT_EXPORT_API int bluetooth_hdp_connect(const char *app_handle,
450 bt_hdp_qos_type_t channel_type,
451 const bluetooth_device_address_t *device_address)
454 hdp_app_list_t *list;
455 bt_user_info_t *user_info;
457 BT_CHECK_ENABLED(return);
458 BT_CHECK_PARAMETER(app_handle, return);
459 BT_CHECK_PARAMETER(device_address, return);
461 user_info = _bt_get_user_data(BT_COMMON);
462 retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
464 list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
466 BT_ERR("**** list not found for %s ******\n", app_handle);
467 return BLUETOOTH_ERROR_INVALID_PARAM;
470 BT_DBG("app_handle: %s", app_handle);
473 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
475 g_array_append_vals(in_param1, app_handle, (strlen(app_handle) + 1));
476 g_array_append_vals(in_param2, &channel_type, sizeof(bt_hdp_qos_type_t));
477 g_array_append_vals(in_param3, device_address, sizeof(bluetooth_device_address_t));
479 result = _bt_send_request_async(BT_BLUEZ_SERVICE,
480 BT_HDP_CONNECT, in_param1, in_param2, in_param3, in_param4,
481 user_info->cb, user_info->user_data);
483 if (result != BLUETOOTH_ERROR_NONE)
484 BT_ERR("BT_HDP_CONNECT failed");
486 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
491 BT_EXPORT_API int bluetooth_hdp_disconnect(unsigned int channel_id,
492 const bluetooth_device_address_t *device_address)
495 hdp_obj_info_t *info;
496 bt_user_info_t *user_info;
498 BT_CHECK_ENABLED(return);
499 BT_CHECK_PARAMETER(device_address, return);
501 user_info = _bt_get_user_data(BT_COMMON);
502 retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
504 BT_DBG("channel_id: %d", channel_id);
505 info = __bt_hdp_internal_gslist_obj_find_using_ch_id(channel_id);
507 BT_ERR("*** Could not locate the info for %d*****", channel_id);
508 return BLUETOOTH_ERROR_INVALID_PARAM;
512 BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
514 g_array_append_vals(in_param1, &channel_id, sizeof(int));
515 g_array_append_vals(in_param2, device_address, sizeof(bluetooth_device_address_t));
517 result = _bt_send_request_async(BT_BLUEZ_SERVICE, BT_HDP_DISCONNECT,
518 in_param1, in_param2, in_param3, in_param4,
519 user_info->cb, user_info->user_data);
520 if (result != BLUETOOTH_ERROR_NONE)
521 BT_ERR("BT_HDP_DISCONNECT failed");
523 BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);