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