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