cbf795a0f1c0a56fe0e770b67c77e877f04d96b1
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / bluez_hal / src / bt-hal-hdp-dbus-handler.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Atul Kumar Rai <a.rai@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26
27 #include <gio/gunixfdlist.h>
28 #include <glib.h>
29 #include <gio/gio.h>
30 #include <dlog.h>
31 #include <vconf.h>
32
33 #include "bt-hal-hdp-dbus-handler.h"
34 #include "bt-hal-dbus-common-utils.h"
35 #include "bt-hal-internal.h"
36 #include "bt-hal-msg.h"
37
38 #define BT_HAL_HDP_MANAGER_INTERFACE  "org.bluez.HealthManager1"
39 #define BT_HAL_HDP_DEVICE_INTERFACE  "org.bluez.HealthDevice1"
40 #define BT_HAL_HDP_CHANNEL_INTERFACE  "org.bluez.HealthChannel1"
41 #define BT_HAL_HDP_CHANNEL_ID_MAX 255
42
43 static GSList *app_list;
44 typedef struct {
45         int app_id;
46         char address[BT_HAL_ADDRESS_STRING_SIZE];
47         int channel_id;
48         char *obj_path;
49         int fd;
50 }hdp_conn_info_t;
51
52 typedef struct {
53         int id;
54         char *path;
55         int channel_type;
56         GSList *conn_list;
57 }hdp_app_data_t;
58
59 static handle_stack_msg event_cb = NULL;
60 static int latest_id = -1;
61 static gboolean id_used[BT_HAL_HDP_CHANNEL_ID_MAX];
62
63 static void __hdp_send_conn_event(hdp_conn_info_t *conn_info, int state)
64 {
65         struct hal_ev_hdp_conn_state ev;
66
67         DBG("+");
68
69         /* Prepare to send HDP app registration state event */
70         memset(&ev, 0, sizeof(ev));
71         ev.app_id = conn_info->app_id;
72         _bt_convert_addr_string_to_type(ev.bdaddr, conn_info->address);
73         ev.mdep_index = 0;
74         ev.channel_id = conn_info->channel_id;
75         ev.data_fd = conn_info->fd;
76         ev.channel_state = state;
77         if (!event_cb)
78                 ERR("HDP dbus handler callback not registered");
79         else
80                 event_cb(HAL_EV_HDP_CONN_STATE, (void *)&ev, sizeof(ev));
81
82         DBG("-");
83 }
84
85 int __hdp_assign_channel_id(void)
86 {
87         int index;
88
89         DBG("latest_id: %d", latest_id);
90
91         index = latest_id + 1;
92         if (index >= BT_HAL_HDP_CHANNEL_ID_MAX)
93                 index = 0;
94
95         DBG("index: %d", index);
96
97         while (id_used[index] == TRUE) {
98                 if (index == latest_id) {
99                         /* No available ID */
100                         ERR("All request ID is used");
101                         return -1;
102                 }
103
104                 index++;
105                 if (index >= BT_HAL_HDP_CHANNEL_ID_MAX)
106                         index = 0;
107         }
108
109         latest_id = index;
110         id_used[index] = TRUE;
111         DBG("Assigned Id: %d", latest_id);
112
113         return latest_id;
114 }
115
116 void __hdp_delete_channnel_id(int id)
117 {
118         if (id >= BT_HAL_HDP_CHANNEL_ID_MAX || id < 0) {
119                 ERR("Invalid id %d", id);
120                 return;
121         }
122
123         id_used[id] = FALSE;
124         latest_id = id - 1;
125         DBG("id: %d, latest_id: %d", id, latest_id);
126 }
127
128 static hdp_app_data_t *__get_hdp_app_by_id(int id)
129 {
130         GSList *l;
131
132         for (l = app_list; l != NULL; l = l->next) {
133                 hdp_app_data_t *app = l->data;
134                 if (app && app->id == id)
135                         return app;
136         }
137
138         return NULL;
139 }
140
141 static hdp_app_data_t *__get_hdp_app_by_path(char *app_path)
142 {
143         GSList *l;
144
145         if (!app_path)
146                 return NULL;
147
148         for (l = app_list; l != NULL; l = l->next) {
149                 hdp_app_data_t *app = l->data;
150                 if (app && 0 == g_strcmp0(app->path, app_path))
151                         return app;
152         }
153
154         return NULL;
155 }
156
157 static hdp_conn_info_t *__hdp_find_conn_info_by_ch_path(const char *channel_path)
158 {
159         GSList *l;
160         GSList *l1;
161
162         if (!channel_path)
163                 return NULL;
164
165         for (l = app_list; l != NULL; l = l->next) {
166                 hdp_app_data_t *app = l->data;
167                 if (!app)
168                         continue;
169
170                 for (l1 = app->conn_list; l1 != NULL; l1 = l1->next) {
171                         hdp_conn_info_t *info = l1->data;
172                         if (info && 0 == g_strcmp0(info->obj_path, channel_path))
173                         return info;
174                 }
175         }
176
177         return NULL;
178 }
179
180 static hdp_conn_info_t *__hdp_find_conn_info_by_ch_id(int channel_id)
181 {
182         GSList *l;
183         GSList *l1;
184
185         for (l = app_list; l != NULL; l = l->next) {
186                 hdp_app_data_t *app = l->data;
187                 if (!app)
188                         continue;
189
190                 for (l1 = app->conn_list; l1 != NULL; l1 = l1->next) {
191                         hdp_conn_info_t *info = l1->data;
192                         if (info && info->channel_id == channel_id)
193                         return info;
194                 }
195         }
196
197         return NULL;
198 }
199
200 static hdp_conn_info_t *__hdp_app_create_incomming_conn_info(const char *path)
201 {
202         hdp_conn_info_t *conn_info = NULL;
203         hdp_app_data_t *app;
204         GDBusConnection *conn;
205         GDBusProxy *proxy;
206         GVariantIter *property_iter;
207         const char *property;
208         GVariant *value = NULL;
209         GVariant *reply;
210         GError *err = NULL;
211         char *device = NULL;
212         char *dev_path;
213         char *app_path = NULL;
214         char *type_qos = NULL;
215         gsize len;
216
217         DBG("+");
218
219         conn = _bt_get_system_gconn();
220         if(!conn) {
221                 ERR("_bt_get_system_gconn returned NULL, return");
222                 return NULL;
223         }
224
225         /* Retrive device info */
226         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
227                         NULL,
228                         BT_HAL_BLUEZ_NAME,
229                         path,
230                         BT_HAL_PROPERTIES_INTERFACE,
231                         NULL, &err);
232         if (!proxy) {
233                 ERR("Unable to create proxy: %s", err->message);
234                 g_clear_error(&err);
235                 return NULL;
236         }
237
238         dev_path = g_strdup(BT_HAL_HDP_CHANNEL_INTERFACE);
239         reply = g_dbus_proxy_call_sync(proxy, "GetAll",
240                         g_variant_new("(s)", dev_path),
241                         G_DBUS_CALL_FLAGS_NONE,
242                         -1, NULL, &err);
243         g_free(dev_path);
244         g_object_unref(proxy);
245         if (!reply) {
246                 ERR(" HDP:dbus Can't get the reply");
247                 if (err) {
248                         ERR("%s", err->message);;
249                         g_clear_error(&err);
250                 }
251                 return NULL;
252         }
253
254         g_variant_get(reply, "(a{sv})", &property_iter);
255         while (g_variant_iter_loop(property_iter, "{sv}", &property, &value)) {
256                 DBG("String received = %s\n", property);
257                 if (g_strcmp0("Type", property) == 0)
258                         type_qos = g_variant_dup_string(value, &len);
259                 else if (g_strcmp0("Device", property) == 0)
260                         device = g_variant_dup_string(value, &len);
261                 else if (g_strcmp0("Application", property) == 0)
262                         app_path = g_variant_dup_string(value, &len);
263         }
264
265         DBG("QOS = %s, Device = %s, Apphandler = %s", type_qos, device, app_path);
266         g_variant_iter_free(property_iter);
267         g_variant_unref(reply);
268         g_free(device);
269
270         if (!type_qos || !app_path) {
271                 ERR("Pasing failed");
272                 goto free;
273         }
274
275         app = __get_hdp_app_by_path(app_path);
276         if (!app) {
277                 ERR("Could not find the app with path: %s", app_path);
278                 goto free;
279         }
280
281         conn_info = g_new0(hdp_conn_info_t, 1);
282         conn_info->channel_id = __hdp_assign_channel_id();
283         _bt_convert_device_path_to_address(path, conn_info->address);
284         conn_info->app_id = app->id;
285         conn_info->fd = -1;
286
287         DBG("App Id: %d, remote_address: %s", app->id, conn_info->address);
288         app->conn_list = g_slist_append(app->conn_list, conn_info);
289
290 free:
291         g_free(type_qos);
292         g_free(app_path);
293
294         DBG("-");
295         return conn_info;
296 }
297
298 static void __hdp_free_conn_info(hdp_conn_info_t *conn_info)
299 {
300         DBG("+");
301
302         if (!conn_info) {
303                 ERR("conn_info is NULL");
304                 return;
305         }
306
307         __hdp_delete_channnel_id(conn_info->channel_id);
308         if (0 < conn_info->fd)
309                 close(conn_info->fd);
310         g_free(conn_info->obj_path);
311         g_free(conn_info);
312
313         DBG("-");
314 }
315
316 static void __hdp_free_app_data(hdp_app_data_t *app)
317 {
318         DBG("+");
319
320         g_slist_foreach(app->conn_list, (GFunc)__hdp_free_conn_info, NULL);
321         g_free(app->conn_list);
322         g_free(app->path);
323         g_free(app);
324
325         DBG("-");
326 }
327
328 static int __hdp_acquire_fd(const char *path)
329 {
330         GDBusConnection *conn;
331         GDBusProxy *proxy;
332         GVariant *reply;
333         GUnixFDList *out_fd_list = NULL;
334         GError *err = NULL;
335         int index;
336         int fd;
337
338         DBG("+");
339
340         conn = _bt_get_system_gconn();
341         if(!conn) {
342                 ERR("_bt_get_system_gconn returned NULL, return");
343                 return  -1;
344         }
345
346         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
347                         NULL,
348                         BT_HAL_BLUEZ_NAME,
349                         path,
350                         BT_HAL_HDP_CHANNEL_INTERFACE,
351                         NULL, &err);
352         if (!proxy) {
353                 ERR("Unable to create proxy: %s", err->message);
354                 g_clear_error(&err);
355                 return -1;
356         }
357
358         reply = g_dbus_proxy_call_with_unix_fd_list_sync(proxy,
359                         "Acquire",
360                         NULL, G_DBUS_CALL_FLAGS_NONE,
361                         -1, NULL, &out_fd_list,
362                         NULL, &err);
363         g_object_unref(proxy);
364         if (!reply) {
365                 ERR(" HDP:****** dbus Can't create application ****");
366                 if (err) {
367                         ERR("%s", err->message);;
368                         g_clear_error(&err);
369                 }
370
371                 return -1;
372         }
373
374         g_variant_get(reply, "(h)", &index);
375         fd = g_unix_fd_list_get(out_fd_list, index, NULL);
376
377         INFO("File Descriptor = %d, Dev_path = %s \n", fd, path);
378         g_variant_unref(reply);
379         g_object_unref(out_fd_list);
380
381         DBG("-");
382         return fd;
383 }
384
385 static void __hdp_handle_connect(GVariant *parameters)
386 {
387         hdp_conn_info_t *conn_info = NULL;
388         const char *obj_channel_path;
389         int fd;
390
391         DBG("+");
392
393         g_variant_get(parameters, "(&o)", &obj_channel_path);
394         INFO("Channel connected, Path = %s", obj_channel_path);
395
396         conn_info = __hdp_find_conn_info_by_ch_path(obj_channel_path);
397
398         fd = __hdp_acquire_fd(obj_channel_path);
399         if (0 > fd) {
400                 ERR("__hdp_acquire_fd failed");
401                 goto err;
402         }
403
404         if (!conn_info) {
405                 INFO("conn_info not found, incomming connection request");
406                 /* Create hdp app connection info */
407                 conn_info = __hdp_app_create_incomming_conn_info(obj_channel_path);
408                 if (!conn_info) {
409                         ERR("Could not create app conn info");
410                         close(fd);
411                         return;
412                 }
413         }
414
415         conn_info->fd = fd;
416         conn_info->obj_path = g_strdup(obj_channel_path);
417         /* Send channel_connect callback with status: success */
418         __hdp_send_conn_event(conn_info, BTHL_CONN_STATE_CONNECTED);
419
420         DBG("-");
421         return;
422 err:
423         if (conn_info) {
424                 hdp_app_data_t *app = __get_hdp_app_by_id(conn_info->app_id);
425
426                 ERR("Outgoing connection failed for app_id:%d, send event", conn_info->app_id);
427                 /* Send channel_connect callback with status: disconnected and fd = -1 */
428                 __hdp_send_conn_event(conn_info, BTHL_CONN_STATE_DISCONNECTED);
429                 app->conn_list = g_slist_remove(app->conn_list, conn_info);
430                 __hdp_free_conn_info(conn_info);
431         }
432 }
433
434 static void __hdp_handle_disconnect(GVariant *parameters,
435                 const gchar *object_path)
436 {
437         const char *obj_channel_path;
438         hdp_app_data_t *app;
439         hdp_conn_info_t *conn_info;
440
441         DBG("+");
442
443         g_variant_get(parameters, "(&o)", &obj_channel_path);
444         INFO("Channel Deleted, Path = %s, channel_path: %s",
445                         object_path, obj_channel_path);
446
447         conn_info = __hdp_find_conn_info_by_ch_path(obj_channel_path);
448         if (!conn_info) {
449                 INFO("No conn_info found for channel path:%s", obj_channel_path);
450                 return;
451         }
452
453         /* Send channel_connect callback with status: success */
454         __hdp_send_conn_event(conn_info, BTHL_CONN_STATE_DESTROYED);
455
456         app = __get_hdp_app_by_id(conn_info->app_id);
457         app->conn_list = g_slist_remove(app->conn_list, conn_info);
458         __hdp_free_conn_info(conn_info);
459
460         DBG("-");
461 }
462
463 static void __hdp_handle_property_changed(GVariant *parameters)
464 {
465         char *property = NULL;
466         GVariant *value = NULL;
467         char *obj_main_channel_path = NULL;
468         GVariantIter *property_iter = NULL;
469         gsize len;
470
471         DBG("+");
472
473         g_variant_get(parameters, "(a{sv})", &property_iter);
474         while (g_variant_iter_loop(property_iter, "{sv}", &property, &value)) {
475                 if (g_strcmp0("MainChannel", property) == 0) {
476                         INFO("Property MainChannel received");
477                         obj_main_channel_path = g_variant_dup_string(value, &len);
478                         DBG("Main Channel  Path = %s", obj_main_channel_path);
479                         break;
480                 }
481         }
482         g_variant_iter_free(property_iter);
483         g_free(property);
484         g_variant_unref(value);
485         g_free(obj_main_channel_path);
486
487         DBG("-");
488 }
489
490 static void __hdp_event_filter(GDBusConnection *connection,
491                 const gchar *sender_name,
492                 const gchar *object_path,
493                 const gchar *interface_name,
494                 const gchar *signal_name,
495                 GVariant *parameters,
496                 gpointer user_data)
497 {
498         DBG("Path = %s", object_path);
499         if (object_path == NULL || g_strcmp0(object_path, "/") == 0)
500                 return;
501
502         if (signal_name == NULL)
503                 return;
504
505         if (strcasecmp(signal_name, "ChannelConnected") == 0)
506                 __hdp_handle_connect(parameters);
507
508         else if (strcasecmp(signal_name, "ChannelDeleted") == 0)
509                 __hdp_handle_disconnect(parameters, object_path);
510
511         else if (strcasecmp(signal_name, "PropertyChanged") == 0)
512                 __hdp_handle_property_changed(parameters);
513
514         return;
515 }
516
517 static int __hdp_filter_subscribe_signal(GDBusConnection *conn,
518                                 gboolean subscribe)
519 {
520         static guint subs_add_filter_id = 0;
521
522         if (conn == NULL)
523                 return BT_HAL_ERROR_INVALID_PARAM;
524
525         if (subscribe && subs_add_filter_id) {
526         }
527
528         if (subscribe) {
529                 if (subs_add_filter_id == 0) {
530                         subs_add_filter_id = g_dbus_connection_signal_subscribe(
531                                         conn, NULL, BT_HAL_HDP_DEVICE_INTERFACE,
532                                         NULL, NULL, NULL, 0,
533                                         __hdp_event_filter, NULL, NULL);
534                 } else {
535                         INFO("Signal already subscribed");
536                 }
537         } else {
538                 if (subs_add_filter_id > 0) {
539                         g_dbus_connection_signal_unsubscribe(conn,
540                                         subs_add_filter_id);
541                         subs_add_filter_id = 0;
542                 }
543         }
544
545         return BT_HAL_ERROR_NONE;
546 }
547
548 static int __hdp_add_filter(void)
549 {
550         static GDBusConnection *hdp_conn;
551
552         DBG("+");
553
554         hdp_conn = _bt_get_system_gconn();
555         if(!hdp_conn) {
556                 ERR("_bt_get_system_gconn returned NULL, return");
557                 return BT_HAL_ERROR_INTERNAL;
558         }
559
560         return __hdp_filter_subscribe_signal(hdp_conn, TRUE);
561
562         DBG("-");
563 }
564
565 static int __hdp_remove_filter(void)
566 {
567         static GDBusConnection *hdp_conn;
568
569         DBG("+");
570
571         hdp_conn = _bt_get_system_gconn();
572         if(!hdp_conn) {
573                 ERR("_bt_get_system_gconn returned NULL, return");
574                 return BT_HAL_ERROR_INTERNAL;
575         }
576
577         return __hdp_filter_subscribe_signal(hdp_conn, FALSE);
578
579         DBG("-");
580 }
581
582 static void __hdp_send_app_reg_event(int app_id, unsigned int state)
583 {
584         struct hal_ev_hdp_app_reg_state ev;
585
586         DBG("+");
587
588         /* Prepare to send HDP app registration state event */
589         memset(&ev, 0, sizeof(ev));
590         ev.app_id = app_id;
591         ev.state = state;
592         if (!event_cb)
593                 ERR("HDP dbus handler callback not registered");
594         else
595                 event_cb(HAL_EV_HDP_APP_REG_STATE, (void *)&ev, sizeof(ev));
596
597         DBG("-");
598 }
599
600 static gboolean __hdp_application_created_cb(gpointer data)
601 {
602         hdp_app_data_t *app = data;
603
604         DBG("+");
605         if (!app) {
606                 ERR("__hdp_application_created_cb called with null app data");
607                 return FALSE;
608         }
609
610         app_list = g_slist_append(app_list, app);
611         if (BT_HAL_ERROR_NONE != __hdp_add_filter()) {
612                 ERR("Funtion failed");
613                 __hdp_send_app_reg_event(app->id, BTHL_APP_REG_STATE_REG_FAILED);
614                 return FALSE;
615         }
616
617         __hdp_send_app_reg_event(app->id, BTHL_APP_REG_STATE_REG_SUCCESS);
618
619         DBG("-");
620         return FALSE;
621 }
622
623 static gboolean  __hdp_application_destroyed_cb(gpointer data)
624 {
625         hdp_app_data_t *app = data;
626         int len;
627
628         DBG("+");
629         if (!app) {
630                 ERR("__hdp_application_destroyed_cb called with null app data");
631                 return FALSE;
632         }
633
634         app_list = g_slist_remove(app_list, app);
635
636         len = g_slist_length(app_list);
637         DBG("List length = %d\n", len);
638         if (0 == len)
639                 __hdp_remove_filter();
640
641         __hdp_send_app_reg_event(app->id, BTHL_APP_REG_STATE_DEREG_SUCCESS);
642         __hdp_free_app_data(app);
643
644         DBG("-");
645         return FALSE;
646 }
647
648 static GDBusProxy *__get_health_device_proxy(char *address)
649 {
650         GDBusConnection *conn;
651         GDBusProxy *hdp_proxy;
652         GError *err = NULL;
653         char *adapter_path;
654         char *dev_path;
655
656         DBG("+");
657
658         adapter_path = _bt_hal_get_adapter_path();
659         if (!adapter_path) {
660                 ERR("Could not get adapter path");
661                 return NULL;
662         }
663
664         dev_path = g_strdup_printf("%s/dev_%s", adapter_path, address);
665         if (!dev_path) {
666                 ERR("Failed to create dev_path");
667                 return NULL;
668         }
669
670         g_strdelimit(dev_path, ":", '_');
671         DBG("dev_path: %s", dev_path);
672
673         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
674         if(!conn) {
675                 ERR("ERROR: Can't get on system bus [%s]", err->message);
676                 g_clear_error(&err);
677                 g_free(dev_path);
678                 return NULL;
679         }
680
681         hdp_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
682                         NULL, BT_HAL_BLUEZ_NAME,
683                         dev_path, BT_HAL_HDP_DEVICE_INTERFACE,
684                         NULL, NULL);
685         if (!hdp_proxy)
686                 ERR("Failed to get the HDP server proxy");
687         g_object_unref(conn);
688         g_free(dev_path);
689
690         DBG("-");
691         return hdp_proxy;
692 }
693
694 static void __hdp_connect_request_cb(GDBusProxy *hdp_proxy,
695                 GAsyncResult *res, gpointer user_data)
696 {
697         GVariant *reply;
698         GError *err = NULL;
699         hdp_conn_info_t *conn_info = user_data;
700         hdp_app_data_t *app;
701         char *obj_path = NULL;
702
703         DBG("+");
704
705         reply = g_dbus_proxy_call_finish(hdp_proxy, res, &err);
706         g_object_unref(hdp_proxy);
707         if (!reply) {
708                 if (err) {
709                         ERR("HDP connection Dbus Call Error: %s", err->message);
710                         g_clear_error(&err);
711                 }
712                 /* Send channel_connect callback with status: disconnected and fd = -1 */
713                 __hdp_send_conn_event(conn_info, BTHL_CONN_STATE_DISCONNECTED);
714                 __hdp_free_conn_info(conn_info);
715                 return;
716         }
717
718         g_variant_get(reply, "(&o)", &obj_path);
719         DBG("Obj Path returned = %s\n", obj_path);
720         conn_info->obj_path = g_strdup(obj_path);
721
722         app = __get_hdp_app_by_id(conn_info->app_id);
723         if (!app) {
724                 ERR("No app with app_id: %d exists");
725                 __hdp_free_conn_info(conn_info);
726                 return;
727         }
728
729         app->conn_list = g_slist_append(app->conn_list, conn_info);
730         DBG("-");
731 }
732
733 static void __hdp_disconnect_request_cb(GDBusProxy *hdp_proxy,
734                 GAsyncResult *res, gpointer user_data)
735 {
736         hdp_conn_info_t *conn_info = user_data;
737         GVariant *reply;
738         GError *err = NULL;
739
740         DBG("+");
741
742         reply = g_dbus_proxy_call_finish(hdp_proxy, res, &err);
743         g_object_unref(hdp_proxy);
744         if (!reply) {
745                 if (err) {
746                         ERR("HDP disconnection Dbus Call Error: %s", err->message);
747                         g_clear_error(&err);
748                 }
749
750                 /* Send channel_connect callback with status: connected */
751                 __hdp_send_conn_event(conn_info, BTHL_CONN_STATE_CONNECTED);
752                 return;
753         }
754
755         DBG("-");
756 }
757
758 bt_status_t _bt_hal_dbus_handler_hdp_register_application(int role,
759                 int data_type, int channel_type, const char *description, int *app_id)
760 {
761         GDBusConnection *conn;
762         GDBusProxy *proxy = NULL;
763         GVariantBuilder *builder;
764         const char *key_type;
765         const char *svalue;
766         guint16 value;
767         GVariant *reply = NULL;
768         char *app_path;
769         GError *err = NULL;
770         hdp_app_data_t *app;
771
772         DBG("+");
773
774         conn = _bt_get_system_gconn();
775         if(!conn) {
776                 ERR("_bt_get_system_gconn returned NULL, return");
777                 return BT_STATUS_FAIL;
778         }
779
780         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
781                         NULL,
782                         BT_HAL_BLUEZ_NAME,
783                         "/org/bluez",
784                         BT_HAL_HDP_MANAGER_INTERFACE,
785                         NULL, &err);
786         if (!proxy) {
787                 ERR("Unable to create proxy: %s", err->message);
788                 g_clear_error(&err);
789                 return BT_STATUS_FAIL;
790         }
791
792         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
793
794         key_type = "DataType";
795         value = (guint16)data_type;
796         g_variant_builder_add(builder, "{sv}", key_type, g_variant_new("q", value));
797
798         key_type = "Role";
799         svalue = (role == BTHL_MDEP_ROLE_SINK) ? "Sink" : "Source";
800         g_variant_builder_add(builder, "{sv}", key_type, g_variant_new("s", svalue));
801
802         key_type = "Description";
803         svalue = (description) ? description : "Health Device";
804         g_variant_builder_add(builder, "{sv}", key_type, g_variant_new("s", svalue));
805
806         if (role == BTHL_MDEP_ROLE_SOURCE) {
807                 key_type = "ChannelType";
808                 if (channel_type == BTHL_CHANNEL_TYPE_RELIABLE) {
809                         svalue = "reliable";
810                         DBG("%s : %s", key_type, svalue);
811                 } else if (channel_type == BTHL_CHANNEL_TYPE_STREAMING) {
812                         svalue = "streaming";
813                         DBG("%s : %s", key_type, svalue);
814                 } else {
815                         g_variant_builder_unref(builder);
816                         g_object_unref(proxy);
817                         return BT_STATUS_PARM_INVALID;
818                 }
819
820                 g_variant_builder_add(builder, "{sv}", key_type, g_variant_new("s", svalue));
821         }
822
823         reply = g_dbus_proxy_call_sync(proxy, "CreateApplication",
824                         g_variant_new("(a{sv})", builder),
825                         G_DBUS_CALL_FLAGS_NONE, -1,
826                         NULL, &err);
827         g_variant_builder_unref(builder);
828         g_object_unref(proxy);
829         if (!reply) {
830                 ERR(" HDP:dbus Can't create application");
831                 if (err) {
832                         ERR("%s", err->message);
833                         g_clear_error(&err);
834                 }
835                 return BT_STATUS_FAIL;
836         }
837
838         g_variant_get(reply, "(&o)", &app_path);
839         DBG("Created health application: %s", (char *)app_path);
840
841         app = g_new0(hdp_app_data_t, 1);
842         app->path = g_strdup(app_path);
843         sscanf(app_path, "/org/bluez/health_app_%d", &(app->id));
844         app->channel_type = channel_type;
845         g_variant_unref(reply);
846
847         *app_id = app->id;
848         DBG("App Id: %d", *app_id);
849
850         g_idle_add(__hdp_application_created_cb, (gpointer)app);
851
852         return BT_STATUS_SUCCESS;
853 }
854
855 bt_status_t _bt_hal_dbus_handler_hdp_unregister_application(int app_id)
856 {
857         GDBusConnection *conn;
858         GDBusProxy *proxy = NULL;
859         GVariant *reply = NULL;
860         GError *err = NULL;
861         hdp_app_data_t *app;
862
863         DBG("+");
864
865         DBG("app_id: %d", app_id);
866         app = __get_hdp_app_by_id(app_id);
867         if (!app) {
868                 ERR("No app with app_id: %d exists");
869                 return BT_STATUS_PARM_INVALID;
870         }
871
872         conn = _bt_get_system_gconn();
873         if(!conn) {
874                 ERR("_bt_get_system_gconn returned NULL, return");
875                 return BT_STATUS_FAIL;
876         }
877
878         proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
879                         NULL,
880                         BT_HAL_BLUEZ_NAME,
881                         "/org/bluez",
882                         BT_HAL_HDP_MANAGER_INTERFACE,
883                         NULL, &err);
884         if (!proxy) {
885                 if (err) {
886                         ERR("Unable to create proxy: %s", err->message);
887                         g_clear_error(&err);
888                 } else {
889                         ERR("Unable to create proxy");
890                 }
891                 return BT_STATUS_FAIL;
892         }
893
894         DBG("app->path: %s", app->path);
895         reply = g_dbus_proxy_call_sync(proxy, "DestroyApplication",
896                         g_variant_new("(o)", app->path),
897                         G_DBUS_CALL_FLAGS_NONE,
898                         -1, NULL, &err);
899         g_object_unref(proxy);
900         if (!reply) {
901                 ERR(" HDP:dbus Can't Destroy application");
902                 if (err) {
903                         ERR("%s", err->message);
904                         g_clear_error(&err);
905                 }
906                 return BT_STATUS_FAIL;
907         }
908
909         g_variant_unref(reply);
910         DBG("Destroyed health application: %s", (char *)app->path);
911         g_idle_add(__hdp_application_destroyed_cb, (gpointer)app);
912         DBG("-");
913
914         return BT_STATUS_SUCCESS;
915 }
916
917 bt_status_t _bt_hal_dbus_handler_hdp_connect_channel(int app_id, bt_bdaddr_t *bd_addr, int *channel_id)
918 {
919         GDBusProxy *hdp_proxy;
920         hdp_app_data_t *app;
921         hdp_conn_info_t *conn_info;
922         char *ch_type;
923         char address[BT_HAL_ADDRESS_STRING_SIZE];
924
925         DBG("+");
926
927         if (!bd_addr) {
928                 ERR("Address is NULL");
929                 return BT_STATUS_PARM_INVALID;
930         }
931
932         _bt_convert_addr_type_to_string(address, bd_addr->address);
933
934         if (!channel_id) {
935                 ERR("channel_id is NULL");
936                 return BT_STATUS_PARM_INVALID;
937         }
938
939         app = __get_hdp_app_by_id(app_id);
940         if (!app) {
941                 ERR("No app with app_id: %d exists", app_id);
942                 return BT_STATUS_PARM_INVALID;
943         }
944
945         if (BTHL_CHANNEL_TYPE_RELIABLE == app->channel_type)
946                 ch_type = "Reliable";
947         else if (BTHL_CHANNEL_TYPE_STREAMING == app->channel_type)
948                 ch_type = "Streaming";
949         else
950                 ch_type = "Any";
951
952         DBG("create conection to %s, channel_type: %s", address, ch_type);
953
954         hdp_proxy = __get_health_device_proxy(address);
955         if (!hdp_proxy) {
956                 ERR("Failed to get the health device proxy");
957                 return BT_STATUS_FAIL;
958         }
959
960         DBG("app path %s", app->path);
961
962         *channel_id = __hdp_assign_channel_id();
963         conn_info = g_new0(hdp_conn_info_t, 1);
964         conn_info->app_id = app->id;
965         g_strlcpy(conn_info->address, address, BT_HAL_ADDRESS_STRING_SIZE);
966         conn_info->channel_id = *channel_id;
967         conn_info->fd = -1;
968
969         g_dbus_proxy_call(hdp_proxy, "CreateChannel",
970                         g_variant_new("(os)", app->path, ch_type),
971                         G_DBUS_CALL_FLAGS_NONE, -1, NULL,
972                         (GAsyncReadyCallback)__hdp_connect_request_cb,
973                         conn_info);
974
975         /* Send channel_connect callback with status: connecting and fd = -1 */
976         __hdp_send_conn_event(conn_info, BTHL_CONN_STATE_CONNECTING);
977         DBG("-");
978
979         return BT_STATUS_SUCCESS;
980 }
981
982 bt_status_t _bt_hal_dbus_handler_hdp_destroy_channel(int channel_id)
983 {
984         GDBusProxy *hdp_proxy;
985         hdp_conn_info_t *conn_info;
986
987         DBG("+");
988
989         conn_info = __hdp_find_conn_info_by_ch_id(channel_id);
990         if (!conn_info) {
991                 ERR("No conn found with channel_id: %d", channel_id);
992                 return BT_STATUS_PARM_INVALID;
993         }
994
995         DBG("Destroy channel with channel_id: %d, remote_addr: %s, obj_path: %s",
996                         channel_id, conn_info->address, conn_info->obj_path);
997
998         hdp_proxy = __get_health_device_proxy(conn_info->address);
999         if (!hdp_proxy) {
1000                 ERR("Failed to get the health device proxy");
1001                 return BT_STATUS_FAIL;
1002         }
1003
1004         g_dbus_proxy_call(hdp_proxy, "DestroyChannel",
1005                         g_variant_new("(o)", conn_info->obj_path),
1006                         G_DBUS_CALL_FLAGS_NONE, -1, NULL,
1007                         (GAsyncReadyCallback)__hdp_disconnect_request_cb,
1008                         conn_info);
1009
1010         /* Send channel_connect callback with status: connecting and fd = -1 */
1011         __hdp_send_conn_event(conn_info, BTHL_CONN_STATE_DISCONNECTING);
1012
1013         DBG("-");
1014         return BT_STATUS_SUCCESS;
1015 }
1016
1017 /* To send stack event to hal-hidhost handler */
1018 void _bt_hal_register_hdp_dbus_handler_cb(handle_stack_msg cb)
1019 {
1020         event_cb = cb;
1021 }
1022
1023 /* To send stack event to hal-hidhost handler */
1024 void _bt_hal_unregister_hdp_dbus_handler_cb()
1025 {
1026         event_cb = NULL;
1027 }