Fix memory leak
[platform/core/connectivity/bluetooth-frwk.git] / bt-api / bt-hdp.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <gio/gio.h>
21 #include <glib.h>
22 #include <string.h>
23 #include <gio/gunixfdlist.h>
24
25 #include "bluetooth-api.h"
26 #include "bt-common.h"
27 #include "bt-internal-types.h"
28
29 #define HDP_BUFFER_SIZE 1024
30 #define BLUEZ_HDP_MANAGER_INTERFACE  "org.bluez.HealthManager1"
31 #define BLUEZ_HDP_DEVICE_INTERFACE  "org.bluez.HealthDevice1"
32 #define BLUEZ_HDP_CHANNEL_INTERFACE  "org.bluez.HealthChannel1"
33
34 typedef struct {
35         char *obj_channel_path;
36         int fd;
37         guint watch_id;
38 } hdp_obj_info_t;
39
40 typedef struct {
41         void *app_handle;
42         GSList *obj_info;
43 } hdp_app_list_t;
44
45 /* Variable for privilege, only for write API,
46   before we should reduce time to bt-service dbus calling
47   -1 : Don't have a permission to access API
48   0 : Initial value, not yet check
49   1 : Have a permission to access API
50 */
51 static int privilege_token;
52
53
54 /**********************************************************************
55 *               Static Functions declaration                            *
56 ***********************************************************************/
57 static int __bt_hdp_internal_create_application(unsigned int data_type,
58                                                 int role,
59                                                 bt_hdp_qos_type_t channel_type,
60                                                 char **app_handle);
61
62 static void __bt_hdp_internal_event_filter(GDBusConnection *connection,
63                                         const gchar *sender_name,
64                                         const gchar *object_path,
65                                         const gchar *interface_name,
66                                         const gchar *signal_name,
67                                         GVariant *parameters,
68                                         gpointer user_data);
69
70 static void __bt_hdp_internal_handle_connect(GVariant *parameters);
71
72 static void __bt_hdp_internal_handle_disconnect(GVariant *parameters,
73                                 const gchar *object_path);
74
75 static void __bt_hdp_internal_handle_property_changed(GVariant *parameters);
76
77 static int __bt_hdp_internal_add_filter(void);
78
79 static int __bt_hdp_internal_acquire_fd(const char *path);
80
81 static guint __bt_hdp_internal_watch_fd(int file_desc, const char *path);
82
83 static gboolean __bt_hdp_internal_data_received(GIOChannel *gio,
84                                                 GIOCondition cond,
85                                                 gpointer data);
86
87 static int __bt_hdp_internal_destroy_application(const char *app_handle);
88
89 static void __bt_hdp_internal_remove_filter(void);
90
91 static hdp_app_list_t *__bt_hdp_internal_gslist_find_app_handler(void *app_handle);
92
93 static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_fd(int fd);
94
95 static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_path(const char *obj_channel_path);
96
97 /*Global Variables*/
98 static GDBusConnection *g_hdp_dus_conn;
99
100 static GSList *g_app_list = NULL;
101
102 /**********************************************************************
103 *                       Health device APIs (HDP)                        *
104 ***********************************************************************/
105
106 BT_EXPORT_API int bluetooth_hdp_activate(unsigned short data_type,
107                                         bt_hdp_role_type_t role,
108                                         bt_hdp_qos_type_t channel_type,
109                                         char **app_handle)
110 {
111         int result = BLUETOOTH_ERROR_NONE;
112
113         BT_DBG("+");
114
115         BT_CHECK_ENABLED(return);
116
117         /*For source role is mandatory */
118         if (role == HDP_ROLE_SOURCE && channel_type == HDP_QOS_ANY) {
119                 BT_ERR("For source, type is mandatory - Reliable/Streaming");
120                 return BLUETOOTH_ERROR_INVALID_PARAM;
121         }
122
123         result = __bt_hdp_internal_create_application(data_type, role,
124                                                 channel_type, app_handle);
125
126         return result;
127 }
128
129 static void __bt_hdp_obj_info_free(hdp_obj_info_t *info)
130 {
131         if (info) {
132                 g_source_remove(info->watch_id);
133                 close(info->fd);
134                 g_free(info->obj_channel_path);
135                 g_free(info);
136         }
137 }
138
139 static int __bt_hdp_internal_create_application(unsigned int data_type,
140                                         int role,
141                                         bt_hdp_qos_type_t channel_type,
142                                         char **app_handle)
143 {
144         GDBusProxy *proxy = NULL;
145         GVariant *reply = NULL;
146         GVariantBuilder *builder;
147         const char *svalue;
148         const char *key_type;
149         char *app_path;
150         hdp_app_list_t *list;
151         GError *err = NULL;
152         guint16 value;
153         GDBusConnection *conn;
154         int ret = BLUETOOTH_ERROR_NONE;
155
156         BT_DBG("+");
157
158         conn = _bt_gdbus_get_system_gconn();
159         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
160
161         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
162                                         NULL,
163                                         BT_BLUEZ_NAME,
164                                         "/org/bluez",
165                                         BLUEZ_HDP_MANAGER_INTERFACE,
166                                         NULL, &err);
167
168         if (!proxy) {
169                 BT_ERR("Unable to create proxy: %s", err->message);
170                 g_clear_error(&err);
171                 return BLUETOOTH_ERROR_INTERNAL;
172         }
173
174         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
175
176         key_type = "DataType";
177         value = (guint16) data_type;
178         g_variant_builder_add(builder, "{sv}",
179                         key_type, g_variant_new("q",
180                                 value));
181
182         key_type = "Role";
183         /*0-Source,1-Sink*/
184         svalue = (role == HDP_ROLE_SINK) ? "Sink" : "Source";
185         g_variant_builder_add(builder, "{sv}",
186                         key_type, g_variant_new("s",
187                                 svalue));
188
189         key_type = "Description";
190         svalue = "Health Device";
191         g_variant_builder_add(builder, "{sv}",
192                         key_type, g_variant_new("s",
193                                 svalue));
194
195         if (role == HDP_ROLE_SOURCE) {
196                 key_type = "ChannelType";
197                 if (channel_type == HDP_QOS_RELIABLE)
198                         svalue = "reliable";
199                 else if (channel_type == HDP_QOS_STREAMING)
200                         svalue = "streaming";
201
202                 g_variant_builder_add(builder, "{sv}",
203                         key_type, g_variant_new("s",
204                                 svalue));
205         }
206
207         reply = g_dbus_proxy_call_sync(proxy, "CreateApplication",
208                                         g_variant_new("(a{sv})", builder),
209                                         G_DBUS_CALL_FLAGS_NONE, -1,
210                                         NULL, &err);
211
212         g_variant_builder_unref(builder);
213         g_object_unref(proxy);
214
215         if (!reply) {
216                 BT_ERR(" HDP:dbus Can't create application");
217                 if (err) {
218                         BT_ERR("%s", err->message);
219                         if (g_strrstr(err->message, BT_ACCESS_DENIED_MSG))
220                                 ret = BLUETOOTH_ERROR_ACCESS_DENIED;
221                         else
222                                 ret = BLUETOOTH_ERROR_INTERNAL;
223                         g_clear_error(&err);
224                 }
225                 return ret;
226         }
227
228         g_variant_get(reply, "(&o)", &app_path);
229         BT_DBG("Created health application: %s", (char *)app_path);
230
231         ret = __bt_hdp_internal_add_filter();
232
233         if (ret != BLUETOOTH_ERROR_NONE) {
234                 BT_ERR("Funtion failed");
235                 return ret;
236         }
237
238         list = g_new0(hdp_app_list_t, 1);
239         list->app_handle = (void *)g_strdup(app_path);
240         *app_handle = list->app_handle;
241
242         g_app_list = g_slist_append(g_app_list, list);
243
244         g_variant_unref(reply);
245         return BLUETOOTH_ERROR_NONE;
246 }
247
248 static int __bt_hdp_add_filter_subscribe_signal(GDBusConnection *conn,
249                 gboolean subscribe)
250 {
251         static guint subs_add_filter_id = 0;
252
253         if (conn == NULL)
254                 return BLUETOOTH_ERROR_INVALID_PARAM;
255
256         if (subscribe) {
257                 if (subs_add_filter_id == 0) {
258                         subs_add_filter_id = g_dbus_connection_signal_subscribe(
259                                 conn, NULL, BLUEZ_HDP_DEVICE_INTERFACE,
260                                 NULL, NULL, NULL, 0,
261                                 __bt_hdp_internal_event_filter, NULL, NULL);
262                 }
263         } else {
264                 if (subs_add_filter_id > 0) {
265                         g_dbus_connection_signal_unsubscribe(conn,
266                                         subs_add_filter_id);
267                         subs_add_filter_id = 0;
268                 }
269         }
270         return BLUETOOTH_ERROR_NONE;
271 }
272
273 static int __bt_hdp_internal_add_filter(void)
274 {
275         BT_DBG("+");
276
277         /*Single process only one signal registration is required */
278         if (g_hdp_dus_conn) {
279                 BT_ERR("g_hdp_dus_conn already exist");
280                 return BLUETOOTH_ERROR_NONE;
281         }
282
283         g_hdp_dus_conn = _bt_gdbus_get_system_gconn();
284         retv_if(g_hdp_dus_conn == NULL, BLUETOOTH_ERROR_INTERNAL);
285
286
287         return __bt_hdp_add_filter_subscribe_signal(g_hdp_dus_conn, TRUE);
288
289         BT_DBG("-\n");
290 }
291
292 static void __bt_hdp_internal_event_filter(GDBusConnection *connection,
293                                         const gchar *sender_name,
294                                         const gchar *object_path,
295                                         const gchar *interface_name,
296                                         const gchar *signal_name,
297                                         GVariant *parameters,
298                                         gpointer user_data)
299 {
300         BT_DBG("Path = %s\n", object_path);
301         if (object_path == NULL || g_strcmp0(object_path, "/") == 0)
302                 return;
303
304         if (signal_name == NULL)
305                 return;
306
307         if (strcasecmp(signal_name, "ChannelConnected") == 0) 
308                 __bt_hdp_internal_handle_connect(parameters);
309
310         else if (strcasecmp(signal_name, "ChannelDeleted") == 0)
311                 __bt_hdp_internal_handle_disconnect(parameters, object_path);
312
313         else if (strcasecmp(signal_name, "PropertyChanged") == 0)
314                 __bt_hdp_internal_handle_property_changed(parameters);
315
316         return;
317 }
318
319 static void __bt_hdp_internal_handle_connect(GVariant *parameters)
320 {
321         BT_DBG("+");
322         const char *obj_channel_path;
323         bt_user_info_t *user_info;
324         int ret;
325
326         BT_INFO("*********Signal - ChannelConnected******\n\n");
327         g_variant_get(parameters, "(&o)", &obj_channel_path);
328
329         BT_INFO("Channel connected, Path = %s", obj_channel_path);
330
331         user_info = _bt_get_user_data(BT_COMMON);
332         if (user_info == NULL || user_info->cb == NULL)
333                 return;
334
335         ret = __bt_hdp_internal_acquire_fd(obj_channel_path);
336         if (ret != BLUETOOTH_ERROR_NONE) {
337                 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_CONNECTED,
338                                 BLUETOOTH_ERROR_CONNECTION_ERROR, NULL,
339                                 user_info->cb, user_info->user_data);
340         }
341         BT_DBG("-");
342 }
343
344 static void __bt_hdp_internal_handle_disconnect(GVariant *parameters,
345                                         const gchar *object_path)
346 {
347         const char *obj_channel_path;
348         char address[BT_ADDRESS_STRING_SIZE] = { 0, };
349         bluetooth_device_address_t device_addr = { {0} };
350         bt_hdp_disconnected_t dis_ind;
351         hdp_obj_info_t *info;
352         bt_user_info_t *user_info;
353
354         BT_INFO("+********Signal - ChannelDeleted ******\n\n");
355         BT_DBG("Path = %s", object_path);
356
357         g_variant_get(parameters, "(&o)", &obj_channel_path);
358
359         BT_INFO("Channel Deleted, Path = %s", obj_channel_path);
360
361         info = __bt_hdp_internal_gslist_obj_find_using_path(obj_channel_path);
362         if (!info) {
363                 BT_ERR("No obj info for ob_channel_path [%s]\n", obj_channel_path);
364                 return;
365         }
366
367         /*Since bluetoothd is not sending the ChannelDeleted signal */
368         _bt_convert_device_path_to_address(object_path, address);
369
370         _bt_convert_addr_string_to_type(device_addr.addr, address);
371
372         dis_ind.channel_id = info->fd;
373         dis_ind.device_address = device_addr;
374
375         user_info = _bt_get_user_data(BT_COMMON);
376
377         if (user_info->cb) {
378                 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DISCONNECTED,
379                                 BLUETOOTH_ERROR_NONE, &dis_ind,
380                                 user_info->cb, user_info->user_data);
381         }
382
383         BT_DBG(" Removed connection from list\n");
384
385         __bt_hdp_obj_info_free(info);
386
387 }
388
389 static void __bt_hdp_internal_handle_property_changed(GVariant *parameters)
390 {
391         char *property = NULL;
392         GVariant *value = NULL;
393         gsize len;
394         char *obj_main_channel_path = NULL;
395         GVariantIter *property_iter;
396
397         BT_DBG("+*******Signal - PropertyChanged*******\n");
398
399         g_variant_get (parameters, "(a{sv})", &property_iter);
400
401         while (g_variant_iter_loop(property_iter, "{sv}", &property, &value)) {
402                 if (g_strcmp0("MainChannel", property) == 0) {
403                         BT_INFO("Property MainChannel received");
404                         obj_main_channel_path = g_variant_dup_string (value, &len);
405                         BT_DBG("Main Channel  Path = %s", obj_main_channel_path);
406                         break;
407                 }
408         }
409         g_variant_iter_free(property_iter);
410
411         g_free(property);
412         g_variant_unref(value);
413         g_free(obj_main_channel_path);
414         BT_DBG("-*************\n");
415 }
416
417 static int __bt_hdp_internal_acquire_fd(const char *path)
418 {
419         char address[BT_ADDRESS_STRING_SIZE] = { 0, };
420         bluetooth_device_address_t device_addr = { {0} };
421         const char *property;
422         GVariant *value = NULL;
423         char *type_qos = NULL;
424         char *device = NULL;
425         char *app_handle = NULL;
426         hdp_app_list_t *list = NULL;
427         GDBusProxy *proxy = NULL;
428         GVariant *reply = NULL;
429         GDBusConnection *conn;
430         bt_hdp_connected_t conn_ind;
431         GError *err = NULL;
432         int fd;
433         bt_user_info_t *user_info;
434         char *dev_path;
435         GUnixFDList *out_fd_list;
436         int index;
437         GVariantIter *property_iter;
438         gsize len;
439
440         BT_DBG("+");
441
442         conn = _bt_gdbus_get_system_gconn();
443         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
444
445         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
446                                         NULL,
447                                         BT_BLUEZ_NAME,
448                                         path,
449                                         BLUEZ_HDP_CHANNEL_INTERFACE,
450                                         NULL, &err);
451
452         if (!proxy) {
453                 BT_ERR("Unable to create proxy: %s", err->message);
454                 g_clear_error(&err);
455                 return BLUETOOTH_ERROR_INTERNAL;
456         }
457
458         reply = g_dbus_proxy_call_with_unix_fd_list_sync (proxy,
459                                                    "Acquire",
460                                                    NULL,
461                                                    G_DBUS_CALL_FLAGS_NONE,
462                                                    -1,
463                                                    NULL,
464                                                    &out_fd_list,
465                                                    NULL,
466                                                   &err);
467
468         g_object_unref(proxy);
469
470         if (!reply) {
471                 BT_ERR(" HDP:****** dbus Can't create application ****");
472
473                 if (err) {
474                         BT_ERR("%s", err->message);;
475                         g_clear_error(&err);
476                 }
477
478                 return BLUETOOTH_ERROR_INTERNAL;
479         }
480
481         g_variant_get (reply, "(h)", &index);
482         fd = g_unix_fd_list_get(out_fd_list, index, NULL);
483
484         g_variant_unref(reply);
485
486         BT_DBG("File Descriptor = %d, Dev_path = %s \n", fd, path);
487
488         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
489                                         NULL,
490                                         BT_BLUEZ_NAME,
491                                         path,
492                                         BT_PROPERTIES_INTERFACE,
493                                         NULL, &err);
494
495         if (!proxy) {
496                 BT_ERR("Unable to create proxy: %s", err->message);
497                 g_clear_error(&err);
498                 return BLUETOOTH_ERROR_INTERNAL;
499         }
500
501         dev_path = g_strdup(BLUEZ_HDP_CHANNEL_INTERFACE);
502
503         reply = g_dbus_proxy_call_sync(proxy, "GetAll",
504                                 g_variant_new("(s)", dev_path),
505                                 G_DBUS_CALL_FLAGS_NONE,
506                                 -1,
507                                 NULL,
508                                 &err);
509
510         g_free(dev_path);
511         g_object_unref(proxy);
512
513         if (!reply) {
514                 BT_ERR(" HDP:dbus Can't get the reply");
515
516                 if (err) {
517                         BT_ERR("%s", err->message);;
518                         g_clear_error(&err);
519                 }
520
521                 return BLUETOOTH_ERROR_INTERNAL;
522         }
523
524         g_variant_get (reply, "(a{sv})", &property_iter);
525
526         while (g_variant_iter_loop(property_iter, "{sv}", &property, &value)) {
527                 BT_DBG("String received = %s\n", property);
528
529                 if (g_strcmp0("Type", property) == 0) {
530                         type_qos = g_variant_dup_string (value, &len);
531                 } else if (g_strcmp0("Device", property) == 0) {
532                         device = g_variant_dup_string (value, &len);
533                 } else if (g_strcmp0("Application", property) == 0) {
534                         app_handle = g_variant_dup_string (value, &len);
535                 }
536         }
537         g_variant_iter_free(property_iter);
538
539         g_variant_unref(reply);
540         BT_DBG("QOS = %s, Device = %s, Apphandler = %s",
541                         type_qos, device, app_handle);
542
543         if (NULL == type_qos || NULL == app_handle) {
544                 BT_ERR("Pasing failed\n");
545                 goto error;
546         }
547
548         list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
549
550         /*Only process register with app handle receive the Connected event */
551         if (NULL == list) {
552                 BT_ERR("**** Could not locate the list for %s*****\n", app_handle);
553                 goto error;
554         }
555
556         hdp_obj_info_t *info = g_new0(hdp_obj_info_t, 1);
557         info->fd = fd;
558         info->obj_channel_path = g_strdup(path);
559         info->watch_id = __bt_hdp_internal_watch_fd(fd, info->obj_channel_path);
560         list->obj_info = g_slist_append(list->obj_info, info);
561
562         _bt_convert_device_path_to_address(path, address);
563
564         _bt_convert_addr_string_to_type(device_addr.addr, address);
565
566         conn_ind.app_handle = app_handle;
567         conn_ind.channel_id = fd;
568         conn_ind.device_address = device_addr;
569         conn_ind.type = (g_strcmp0(type_qos, "Reliable") == 0) ?
570                         HDP_QOS_RELIABLE : HDP_QOS_STREAMING;
571
572         BT_DBG("Going to give callback\n");
573
574         user_info = _bt_get_user_data(BT_COMMON);
575
576         if (user_info->cb) {
577                 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_CONNECTED,
578                                 BLUETOOTH_ERROR_NONE, &conn_ind,
579                                 user_info->cb, user_info->user_data);
580         }
581
582         BT_DBG("Updated fd in the list*\n");
583         BT_DBG("-\n");
584
585         g_free(type_qos);
586         g_free(device);
587         g_free(app_handle);
588         return BLUETOOTH_ERROR_NONE;
589 error:
590         g_free(type_qos);
591         g_free(device);
592         g_free(app_handle);
593         return BLUETOOTH_ERROR_INTERNAL;
594 }
595
596 static guint __bt_hdp_internal_watch_fd(int file_desc, const char *path)
597 {
598         GIOChannel *gio;
599         guint id;
600
601         BT_DBG("+");
602
603         gio = g_io_channel_unix_new(file_desc);
604
605         g_io_channel_set_close_on_unref(gio, TRUE);
606
607         id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
608                         __bt_hdp_internal_data_received, (void *)path);
609         BT_DBG("-");
610         return id;
611 }
612
613
614 static void __bt_hdp_internal_handle_disconnect_cb(int sk, const char *path)
615 {
616         char address[BT_ADDRESS_STRING_SIZE] = { 0, };
617         bluetooth_device_address_t device_addr = { {0} };
618         bt_hdp_disconnected_t dis_ind;
619         hdp_obj_info_t *info;
620         bt_user_info_t *user_info;
621
622         BT_INFO("******** Socket Error  ******\n");
623
624         info = __bt_hdp_internal_gslist_obj_find_using_path(path);
625         ret_if(info == NULL);
626
627         /*Since bluetoothd is not sending the ChannelDeleted signal */
628         _bt_convert_device_path_to_address(path, address);
629
630         _bt_convert_addr_string_to_type(device_addr.addr, address);
631
632         dis_ind.channel_id = sk;
633         dis_ind.device_address = device_addr;
634
635         user_info = _bt_get_user_data(BT_COMMON);
636
637         if (user_info->cb) {
638                 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DISCONNECTED,
639                                 BLUETOOTH_ERROR_NONE, &dis_ind,
640                                 user_info->cb, user_info->user_data);
641         }
642
643         BT_DBG(" Removed connection from list\n");
644
645         __bt_hdp_obj_info_free(info);
646 }
647
648 static gboolean __bt_hdp_internal_data_received(GIOChannel *gio,
649                                         GIOCondition cond, gpointer data)
650 {
651         char buff[HDP_BUFFER_SIZE] = { 0, };
652         int sk;
653         int act_read;
654         bt_hdp_data_ind_t data_ind = { 0, };
655         const char *path = (const char *)data;
656         bt_user_info_t *user_info;
657
658         BT_DBG("+");
659
660         sk = g_io_channel_unix_get_fd(gio);
661
662         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
663                 BT_DBG("GIOCondition %d.............path = %s\n", cond, path);
664                 g_io_channel_shutdown(gio, TRUE, NULL);
665                 g_io_channel_unref(gio);
666                  __bt_hdp_internal_handle_disconnect_cb(sk, path);
667                 return FALSE;
668         }
669
670         act_read = recv(sk, (void *)buff, sizeof(buff), 0);
671
672         if (act_read > 0) {
673                 BT_DBG("Received data of %d\n", act_read);
674         } else {
675                 BT_ERR("Read failed.....\n");
676                 return FALSE;
677         }
678
679         data_ind.channel_id = sk;
680         data_ind.buffer = buff;
681         data_ind.size = act_read;
682
683         user_info = _bt_get_user_data(BT_COMMON);
684
685         if (user_info->cb) {
686                 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DATA_RECEIVED,
687                                 BLUETOOTH_ERROR_NONE, &data_ind,
688                                 user_info->cb, user_info->user_data);
689         }
690
691         BT_DBG("-\n");
692
693         return TRUE;
694 }
695
696 BT_EXPORT_API int bluetooth_hdp_deactivate(const char *app_handle)
697 {
698         BT_DBG("+");
699
700         BT_CHECK_ENABLED(return);
701         BT_CHECK_PARAMETER(app_handle, return);
702
703         return __bt_hdp_internal_destroy_application(app_handle);
704 }
705
706 static hdp_app_list_t *__bt_hdp_internal_gslist_find_app_handler(void *app_handle)
707 {
708         GSList *l;
709
710         retv_if(g_app_list == NULL, NULL);
711
712         BT_DBG("List length = %d\n", g_slist_length(g_app_list));
713
714         for (l = g_app_list; l != NULL; l = l->next) {
715                 hdp_app_list_t *list = l->data;
716
717                 if (list) {
718                         if (0 == g_strcmp0((char *)list->app_handle,
719                                                 (char *)app_handle))
720                                 return list;
721                 }
722         }
723         return NULL;
724 }
725
726 static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_fd(int fd)
727 {
728         GSList *l;
729         GSList *iter;
730
731         retv_if(g_app_list == NULL, NULL);
732
733         BT_DBG("List length = %d\n", g_slist_length(g_app_list));
734
735         for (l = g_app_list; l != NULL; l = l->next) {
736                 hdp_app_list_t *list = l->data;
737                 if (!list)
738                         return NULL;
739
740                 for (iter = list->obj_info; iter != NULL; iter = iter->next) {
741                         hdp_obj_info_t *info = iter->data;
742                         if (!info)
743                                 return NULL;
744
745                         if (fd == info->fd)
746                                 return info;
747                 }
748         }
749         return NULL;
750 }
751
752 static hdp_obj_info_t *__bt_hdp_internal_gslist_obj_find_using_path(const char *obj_channel_path)
753 {
754         GSList *l;
755         GSList *iter;
756         hdp_obj_info_t *info = NULL;
757
758         retv_if(g_app_list == NULL, NULL);
759
760         BT_DBG("List length = %d\n", g_slist_length(g_app_list));
761         for (l = g_app_list; l != NULL; l = l->next) {
762                 hdp_app_list_t *list = l->data;
763                 if (!list)
764                         return NULL;
765
766                 for (iter = list->obj_info; iter != NULL; iter = iter->next) {
767                          info = iter->data;
768                         if (!info)
769                                 return NULL;
770
771                         if (0 == g_strcmp0(info->obj_channel_path, obj_channel_path)) {
772                                 list->obj_info = g_slist_remove(list->obj_info, info);
773                                 return info;
774                         }
775                 }
776         }
777         return NULL;
778 }
779
780 static gboolean  __bt_hdp_internal_destroy_application_cb(gpointer data)
781 {
782         const char *app_handle;
783         hdp_app_list_t *list = NULL;
784         app_handle = (const char *)data;
785
786         BT_DBG("+");
787
788         list = __bt_hdp_internal_gslist_find_app_handler((void *)app_handle);
789         if (NULL == list) {
790                 BT_ERR("**** list not found for %s ******\n", app_handle);
791                 return FALSE;
792         }
793
794         g_app_list = g_slist_remove(g_app_list, list);
795
796         g_free(list->app_handle);
797         g_slist_foreach(list->obj_info, (GFunc)__bt_hdp_obj_info_free, NULL);
798         g_free(list);
799
800         BT_DBG("List length = %d\n", g_slist_length(g_app_list));
801
802         if (0 == g_slist_length(g_app_list))
803                 __bt_hdp_internal_remove_filter();
804         BT_DBG("-");
805         return FALSE;
806 }
807
808 static int __bt_hdp_internal_destroy_application(const char *app_handle)
809 {
810         GDBusProxy *proxy = NULL;
811         GVariant *reply = NULL;
812         GError *err = NULL;
813         GDBusConnection *conn;
814         int result = BLUETOOTH_ERROR_NONE;
815
816         conn = _bt_gdbus_get_system_gconn();
817         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
818
819         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
820                                         NULL,
821                                         BT_BLUEZ_NAME,
822                                         "/org/bluez",
823                                         BLUEZ_HDP_MANAGER_INTERFACE,
824                                         NULL, &err);
825
826         if (!proxy) {
827                 BT_ERR("Unable to create proxy: %s", err->message);
828                 g_clear_error(&err);
829                 return BLUETOOTH_ERROR_INTERNAL;
830         }
831
832         reply = g_dbus_proxy_call_sync(proxy, "DestroyApplication",
833                                 g_variant_new("o", app_handle),
834                                 G_DBUS_CALL_FLAGS_NONE,
835                                 -1,
836                                 NULL,
837                                 &err);
838
839         g_object_unref(proxy);
840         if (!reply) {
841                 BT_ERR(" HDP:dbus Can't Destroy application");
842
843                 if (err) {
844                         BT_ERR("%s", err->message);
845                         if (g_strrstr(err->message, BT_ACCESS_DENIED_MSG))
846                                 result  = BLUETOOTH_ERROR_ACCESS_DENIED;
847                         else
848                                 result  = BLUETOOTH_ERROR_INTERNAL;
849                         g_clear_error(&err);
850                 }
851                 return result ;
852         }
853
854         g_variant_unref(reply);
855
856         BT_DBG("Destroyed health application: %s", (char *)app_handle);
857
858         g_idle_add(__bt_hdp_internal_destroy_application_cb,
859                         (gpointer)app_handle);
860
861         return BLUETOOTH_ERROR_NONE;
862 }
863
864 static void __bt_hdp_internal_remove_filter(void)
865 {
866         BT_DBG("+");
867
868         ret_if(g_hdp_dus_conn == NULL);
869
870         __bt_hdp_add_filter_subscribe_signal(g_hdp_dus_conn, FALSE);
871
872         g_hdp_dus_conn = NULL;  /*should not unref here, bcz no ++reff */
873
874         BT_DBG("-");
875 }
876
877 BT_EXPORT_API int bluetooth_hdp_send_data(unsigned int channel_id,
878                                             const char *buffer,
879                                             unsigned int size)
880 {
881         int wbytes = 0;
882         int written = 0;
883         int result;
884
885         BT_DBG("+");
886
887         BT_CHECK_ENABLED(return);
888
889         if ((channel_id == 0) || (NULL == buffer) || (size == 0)) {
890                 BT_ERR("Invalid arguments..\n");
891                 return BLUETOOTH_ERROR_INVALID_PARAM;
892         }
893
894         switch (privilege_token) {
895         case 0:
896                 result = _bt_check_privilege(BT_BLUEZ_SERVICE, BT_HDP_SEND_DATA);
897
898                 if (result == BLUETOOTH_ERROR_NONE) {
899                         privilege_token = 1; /* Have a permission */
900                 } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
901                         BT_ERR("Don't have a privilege to use this API");
902                         privilege_token = -1; /* Don't have a permission */
903                         return BLUETOOTH_ERROR_PERMISSION_DEINED;
904                 } else {
905                         /* Just break - It is not related with permission error */
906                 }
907                 break;
908         case 1:
909                 /* Already have a privilege */
910                 break;
911         case -1:
912                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
913         default:
914                 /* Invalid privilge token value */
915                 return BLUETOOTH_ERROR_INTERNAL;
916         }
917
918         while (wbytes < size) {
919                 written = write(channel_id, buffer + wbytes, size - wbytes);
920                 if (written <= 0) {
921                         BT_ERR("write failed..\n");
922                         return BLUETOOTH_ERROR_NOT_IN_OPERATION;
923                 }
924                 wbytes += written;
925         }
926
927         return BLUETOOTH_ERROR_NONE;
928 }
929
930 static void __bt_hdp_connect_request_cb(GDBusProxy *hdp_proxy,
931                                 GAsyncResult *res, gpointer user_data)
932 {
933         GError *err = NULL;
934         char *obj_connect_path = NULL;
935         bt_hdp_connected_t *conn_ind = user_data;
936         bt_user_info_t *user_info;
937         GVariant *reply = NULL;
938
939         reply = g_dbus_proxy_call_finish(hdp_proxy, res, &err);
940
941         g_object_unref(hdp_proxy);
942
943         if (!reply) {
944                 if (err) {
945                         BT_ERR("HDP connection  Dbus Call Error: %s\n", err->message);
946                         g_clear_error(&err);
947                 }
948
949                 user_info = _bt_get_user_data(BT_COMMON);
950
951                 if (user_info->cb) {
952                         _bt_common_event_cb(BLUETOOTH_EVENT_HDP_CONNECTED,
953                                         BLUETOOTH_ERROR_CONNECTION_ERROR, conn_ind,
954                                         user_info->cb, user_info->user_data);
955                 }
956         } else {
957                 g_variant_get(reply, "(&o)", &obj_connect_path);
958                 BT_DBG("Obj Path returned = %s\n", obj_connect_path);
959         }
960         g_free((void *)conn_ind->app_handle);
961         g_free(conn_ind);
962 }
963
964
965 BT_EXPORT_API int bluetooth_hdp_connect(const char *app_handle,
966                         bt_hdp_qos_type_t channel_type,
967                         const bluetooth_device_address_t *device_address)
968 {
969         GError *err = NULL;
970         GDBusConnection *conn = NULL;
971         GDBusProxy *hdp_proxy = NULL;
972         bt_hdp_connected_t *param;
973         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
974         char default_adapter_path[BT_ADAPTER_OBJECT_PATH_MAX + 1] = { 0 };
975         char *dev_path = NULL;
976         char *role;
977
978         BT_DBG("+");
979
980         BT_CHECK_ENABLED(return);
981         BT_CHECK_PARAMETER(app_handle, return);
982         BT_CHECK_PARAMETER(device_address, return);
983
984         if (_bt_check_privilege(BT_BLUEZ_SERVICE, BT_HDP_CONNECT)
985              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
986                 BT_ERR("Don't have a privilege to use this API");
987                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
988         }
989
990         if (channel_type == HDP_QOS_RELIABLE) {
991                 role = "Reliable";
992         } else if (channel_type == HDP_QOS_STREAMING) {
993                 role = "Streaming";
994         } else if (channel_type == HDP_QOS_ANY) {
995                 role = "Any";
996         } else {
997                 BT_ERR("Invalid channel_type %d", channel_type);
998                 return BLUETOOTH_ERROR_ACCESS_DENIED;
999         }
1000
1001         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1002
1003         if (err) {
1004                 BT_ERR("ERROR: Can't get on system bus [%s]", err->message);
1005                 g_clear_error(&err);
1006                 return BLUETOOTH_ERROR_INTERNAL;
1007         }
1008
1009         /* If the adapter path is wrong, we can think the BT is not enabled. */
1010         if (_bt_get_adapter_path(_bt_gdbus_get_system_gconn(),
1011                                         default_adapter_path) < 0) {
1012                 BT_ERR("Could not get adapter path\n");
1013                 g_object_unref(conn);
1014                 return BLUETOOTH_ERROR_DEVICE_NOT_ENABLED;
1015         }
1016
1017         _bt_convert_addr_type_to_string(address,
1018                                 (unsigned char *)device_address->addr);
1019
1020         BT_DBG("create conection to %s", address);
1021
1022         dev_path = g_strdup_printf("%s/dev_%s", default_adapter_path, address);
1023
1024         if (dev_path == NULL) {
1025                 g_object_unref(conn);
1026                 return BLUETOOTH_ERROR_MEMORY_ALLOCATION;
1027         }
1028
1029         g_strdelimit(dev_path, ":", '_');
1030
1031         BT_DBG("path: %s", dev_path);
1032
1033         hdp_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
1034                                                 NULL, BT_BLUEZ_NAME,
1035                                                 dev_path, BLUEZ_HDP_DEVICE_INTERFACE,
1036                                                 NULL, NULL);
1037         g_object_unref(conn);
1038
1039         if (hdp_proxy == NULL) {
1040                 BT_ERR("Failed to get the HDP server proxy\n");
1041                 g_free(dev_path);
1042                 return BLUETOOTH_ERROR_NOT_PAIRED;
1043         }
1044
1045         BT_DBG("app path %s\n", app_handle);
1046
1047         param = g_new0(bt_hdp_connected_t, 1);
1048         param->app_handle = g_strdup(app_handle);
1049         memcpy(&param->device_address, device_address, BLUETOOTH_ADDRESS_LENGTH);
1050         param->type = channel_type;
1051
1052         g_dbus_proxy_call(hdp_proxy, "CreateChannel",
1053                                 g_variant_new("(os)", app_handle, role),
1054                                 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
1055                                 (GAsyncReadyCallback)__bt_hdp_connect_request_cb,
1056                                 param);
1057
1058         g_free(dev_path);
1059
1060         return BLUETOOTH_ERROR_NONE;
1061 }
1062
1063 static void __bt_hdp_disconnect_request_cb(GDBusProxy *hdp_proxy,
1064                         GAsyncResult *res, gpointer user_data)
1065 {
1066         GError *err = NULL;
1067         bt_hdp_disconnected_t *disconn_ind = user_data;
1068         bt_user_info_t *user_info;
1069         GVariant *reply = NULL;
1070
1071         reply = g_dbus_proxy_call_finish(hdp_proxy, res, &err);
1072         g_object_unref(hdp_proxy);
1073
1074         user_info = _bt_get_user_data(BT_COMMON);
1075         if (user_info == NULL || user_info->cb == NULL) {
1076                 g_free(disconn_ind);
1077                 if (err) {
1078                                 g_clear_error(&err);
1079                         return;
1080                 }
1081                 g_variant_unref(reply);
1082                 return;
1083         }
1084
1085         if (!reply) {
1086                 if (err) {
1087                         BT_ERR("HDP disconnection Dbus Call Error: %s\n",
1088                                                         err->message);
1089                         g_clear_error(&err);
1090                 }
1091
1092                 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DISCONNECTED,
1093                                 BLUETOOTH_ERROR_CONNECTION_ERROR, disconn_ind,
1094                                 user_info->cb, user_info->user_data);
1095         } else {
1096                 _bt_common_event_cb(BLUETOOTH_EVENT_HDP_DISCONNECTED,
1097                                 BLUETOOTH_ERROR_NONE, disconn_ind,
1098                                 user_info->cb, user_info->user_data);
1099                 BT_INFO("HDP disconnection Dbus Call is done\n");
1100                 g_variant_unref(reply);
1101         }
1102
1103         g_free(disconn_ind);
1104 }
1105
1106 BT_EXPORT_API int bluetooth_hdp_disconnect(unsigned int channel_id,
1107                         const bluetooth_device_address_t *device_address)
1108 {
1109         GError *err = NULL;
1110         GDBusConnection *conn = NULL;
1111         GDBusProxy *hdp_proxy = NULL;
1112         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
1113         char default_adapter_path[BT_ADAPTER_OBJECT_PATH_MAX + 1] = { 0 };
1114         char *dev_path = NULL;
1115         bt_hdp_disconnected_t *param;
1116
1117         BT_DBG("+\n");
1118
1119         BT_CHECK_ENABLED(return);
1120         BT_CHECK_PARAMETER(device_address, return);
1121
1122         if (_bt_check_privilege(BT_BLUEZ_SERVICE, BT_HDP_DISCONNECT)
1123              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1124                 BT_ERR("Don't have a privilege to use this API");
1125                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1126         }
1127
1128         hdp_obj_info_t *info =
1129                 __bt_hdp_internal_gslist_obj_find_using_fd(channel_id);
1130         if (NULL == info) {
1131                 BT_ERR("*** Could not locate the list for %d*****\n",
1132                                                         channel_id);
1133                 return BLUETOOTH_ERROR_INVALID_PARAM;
1134         }
1135
1136         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1137
1138         if (err) {
1139                 BT_ERR("ERROR: Can't get on system bus [%s]", err->message);
1140                 g_clear_error(&err);
1141                 return BLUETOOTH_ERROR_INTERNAL;
1142         }
1143
1144         /* If the adapter path is wrong, we can think the BT is not enabled. */
1145         if (_bt_get_adapter_path(_bt_gdbus_get_system_gconn(),
1146                                         default_adapter_path) < 0) {
1147                 BT_ERR("Could not get adapter path\n");
1148                 g_object_unref(conn);
1149                 return BLUETOOTH_ERROR_DEVICE_NOT_ENABLED;
1150         }
1151
1152         _bt_convert_addr_type_to_string(address,
1153                                 (unsigned char *)device_address->addr);
1154
1155         BT_DBG("create conection to  %s\n", address);
1156
1157         dev_path = g_strdup_printf("%s/dev_%s", default_adapter_path, address);
1158
1159         if (dev_path == NULL) {
1160                 g_object_unref(conn);
1161                 return BLUETOOTH_ERROR_MEMORY_ALLOCATION;
1162         }
1163
1164         g_strdelimit(dev_path, ":", '_');
1165
1166         BT_DBG("path  %s\n", dev_path);
1167
1168         hdp_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
1169                                                 NULL, BT_BLUEZ_NAME,
1170                                                 dev_path, BLUEZ_HDP_DEVICE_INTERFACE,
1171                                                 NULL, NULL);
1172
1173         g_object_unref(conn);
1174
1175         if (hdp_proxy == NULL) {
1176                 BT_ERR("Failed to get the HDP proxy\n");
1177                 g_free(dev_path);
1178                 return BLUETOOTH_ERROR_NOT_PAIRED;
1179         }
1180
1181         param = g_new0(bt_hdp_disconnected_t, 1);
1182         param->channel_id = channel_id;
1183         memcpy(&param->device_address, device_address, BLUETOOTH_ADDRESS_LENGTH);
1184
1185         g_dbus_proxy_call(hdp_proxy, "DestroyChannel",
1186                                 g_variant_new("o", info->obj_channel_path),
1187                                 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
1188                                 (GAsyncReadyCallback)__bt_hdp_disconnect_request_cb,
1189                                 param);
1190
1191         g_free(dev_path);
1192         g_free(param);
1193         g_object_unref(hdp_proxy);
1194
1195         return BLUETOOTH_ERROR_NONE;
1196
1197 }