34c34c7ae93713961548a811a1f42e2ecb9ad30e
[platform/core/connectivity/bluetooth-frwk.git] / bt-core / bt-core-dbus-handler.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <gio/gio.h>
19 #include <vconf.h>
20 #include <vconf-keys.h>
21
22 #include "bt-core-adapter.h"
23 #include "bt-core-common.h"
24 #include "bt-core-dbus-handler.h"
25 #include "bt-internal-types.h"
26 #include "bt-core-noti-handler.h"
27 #include "bt-core-main.h"
28
29 #define BT_SERVICE_NAME         "org.projectx.bt"
30 #define BT_SERVICE_PATH         "/org/projectx/bt_service"
31
32 #ifdef TIZEN_FEATURE_BT_HPS
33 #define BT_HPS_SERVICE_NAME "org.projectx.httpproxy"
34 #define BT_HPS_OBJECT_PATH "/org/projectx/httpproxy"
35 #define BT_HPS_INTERFACE_NAME "org.projectx.httpproxy_service"
36 #endif
37
38 static GDBusConnection *service_gconn;
39 static GDBusProxy *service_gproxy;
40 #ifdef TIZEN_FEATURE_BT_HPS
41 static GDBusProxy *hps_gproxy;
42 #endif
43
44 void _bt_core_fill_garray_from_variant(GVariant *var, GArray *param)
45 {
46         char *data;
47         int size;
48
49         size = g_variant_get_size(var);
50         if (size > 0) {
51                 data = (char *)g_variant_get_data(var);
52                 if (data)
53                         param = g_array_append_vals(param, data, size);
54
55         }
56 }
57
58 GDBusConnection * _bt_core_get_gdbus_connection(void)
59 {
60         GError *err = NULL;
61
62         if (service_gconn == NULL)
63                 service_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
64
65         if (!service_gconn) {
66                 if (err) {
67                         BT_ERR("Unable to connect to dbus: %s", err->message);
68                         g_clear_error(&err);
69                 }
70                 return NULL;
71         }
72
73         return service_gconn;
74 }
75
76 static GDBusProxy *__bt_core_gdbus_init_service_proxy(void)
77 {
78         GDBusProxy *proxy;
79         GError *err = NULL;
80         GDBusConnection *conn;
81
82         conn = _bt_core_get_gdbus_connection();
83         if (!conn)
84                 return NULL;
85
86         proxy =  g_dbus_proxy_new_sync(conn,
87                         G_DBUS_PROXY_FLAGS_NONE, NULL,
88                         BT_SERVICE_NAME,
89                         BT_SERVICE_PATH,
90                         BT_SERVICE_NAME,
91                         NULL, &err);
92         if (!proxy) {
93                 if (err) {
94                          BT_ERR("Unable to create proxy: %s", err->message);
95                          g_clear_error(&err);
96                 }
97
98                 return NULL;
99         }
100
101         service_gproxy = proxy;
102
103         return proxy;
104 }
105
106 GDBusProxy *_bt_core_gdbus_get_service_proxy(void)
107 {
108         return (service_gproxy) ? service_gproxy : __bt_core_gdbus_init_service_proxy();
109 }
110
111 #ifdef TIZEN_FEATURE_BT_HPS
112 int _bt_core_start_httpproxy(void)
113 {
114         GVariant *variant = NULL;
115         unsigned char enabled;
116         GError *err = NULL;
117         BT_DBG(" ");
118
119         hps_gproxy = _bt_core_gdbus_get_hps_proxy();
120         if (!hps_gproxy) {
121                 BT_DBG("Couldn't get service proxy");
122                 return -1;
123         }
124
125         variant = g_dbus_proxy_call_sync(hps_gproxy, "enable",
126                                 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
127         if (err) {
128                 BT_ERR("Error : %s" , err->message);
129                 g_clear_error(&err);
130         }
131         if (variant) {
132                 g_variant_get(variant, "(y)", &enabled);
133                 BT_ERR("HPS enabled status 0x%x", enabled);
134         }
135         return 0;
136 }
137
138 int _bt_core_stop_httpproxy(void)
139 {
140         GVariant *variant = NULL;
141         unsigned char enabled;
142         GError *err = NULL;
143         BT_DBG(" ");
144
145         hps_gproxy = _bt_core_gdbus_get_hps_proxy();
146         if (!hps_gproxy) {
147                 BT_DBG("Couldn't get service proxy");
148                 return -1;
149         }
150
151         variant = g_dbus_proxy_call_sync(hps_gproxy, "disable",
152                                 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
153         if (err) {
154                 BT_ERR("Error : %s" , err->message);
155                 g_clear_error(&err);
156         }
157         if (variant) {
158                 g_variant_get(variant, "(y)", &enabled);
159                 BT_ERR("HPS disabled status 0x%x", enabled);
160         }
161         return 0;
162 }
163
164 static GDBusProxy *_bt_core_gdbus_init_hps_proxy(void)
165 {
166         GDBusProxy *proxy;
167         GError *err = NULL;
168         GDBusConnection *conn;
169
170         BT_DBG(" ");
171
172         conn = _bt_core_get_gdbus_connection();
173         if (!conn)
174                 return NULL;
175
176         proxy =  g_dbus_proxy_new_sync(conn,
177                         G_DBUS_PROXY_FLAGS_NONE, NULL,
178                         BT_HPS_SERVICE_NAME,
179                         BT_HPS_OBJECT_PATH,
180                         BT_HPS_INTERFACE_NAME,
181                         NULL, &err);
182         if (proxy == NULL) {
183                 if (err) {
184                          BT_ERR("Unable to create proxy: %s", err->message);
185                          g_clear_error(&err);
186                 }
187                 return NULL;
188         }
189
190         hps_gproxy = proxy;
191
192         return proxy;
193 }
194
195 GDBusProxy *_bt_core_gdbus_get_hps_proxy(void)
196 {
197         return (hps_gproxy) ? hps_gproxy : _bt_core_gdbus_init_hps_proxy();
198 }
199 #endif
200
201 void _bt_core_gdbus_deinit_proxys(void)
202 {
203         BT_DBG("");
204
205         if (service_gproxy) {
206                 g_object_unref(service_gproxy);
207                 service_gproxy = NULL;
208         }
209
210 #ifdef TIZEN_FEATURE_BT_HPS
211         if (hps_gproxy) {
212                 g_object_unref(hps_gproxy);
213                 hps_gproxy = NULL;
214         }
215 #endif
216
217         if (service_gconn) {
218                 g_object_unref(service_gconn);
219                 service_gconn = NULL;
220         }
221 }
222
223 int _bt_core_service_request(int service_type, int service_function,
224                         GArray *in_param1, GArray *in_param2,
225                         GArray *in_param3, GArray *in_param4,
226                         GArray **out_param1)
227 {
228         GDBusProxy  *proxy;
229         GVariant *ret = NULL;
230         GVariant *param1;
231         GVariant *param2;
232         GVariant *param3;
233         GVariant *param4;
234         GVariant *param5;
235
236         int result = BLUETOOTH_ERROR_NONE;
237         GError *error = NULL;
238         GArray *in_param5 = NULL;
239
240         int retry = 5;
241
242         proxy = _bt_core_gdbus_get_service_proxy();
243         if (!proxy)
244                 return BLUETOOTH_ERROR_INTERNAL;
245         in_param5 = g_array_new(TRUE, TRUE, sizeof(gchar));
246
247         while (--retry >= 0) {
248                 param1 = g_variant_new_from_data((const GVariantType *)"ay",
249                                         in_param1->data, in_param1->len,
250                                         TRUE, NULL, NULL);
251                 param2 = g_variant_new_from_data((const GVariantType *)"ay",
252                                         in_param2->data, in_param2->len,
253                                         TRUE, NULL, NULL);
254                 param3 = g_variant_new_from_data((const GVariantType *)"ay",
255                                         in_param3->data, in_param3->len,
256                                         TRUE, NULL, NULL);
257                 param4 = g_variant_new_from_data((const GVariantType *)"ay",
258                                         in_param4->data, in_param4->len,
259                                         TRUE, NULL, NULL);
260                 param5 = g_variant_new_from_data((const GVariantType *)"ay",
261                                         in_param5->data, in_param5->len,
262                                         TRUE, NULL, NULL);
263
264                 ret = g_dbus_proxy_call_sync(proxy, "service_request",
265                                         g_variant_new("(iii@ay@ay@ay@ay@ay)",
266                                                 service_type, service_function,
267                                                 BT_SYNC_REQ, param1,
268                                                 param2, param3,
269                                                 param4, param5),
270                                         G_DBUS_CALL_FLAGS_NONE, 2000,
271                                         NULL, &error);
272                 if (ret == NULL && error != NULL) {
273                         if (error->code == G_IO_ERROR_TIMED_OUT) {
274                                 BT_ERR("D-Bus Timed out.");
275                                 g_clear_error(&error);
276                                 continue;
277                         }
278                 }
279
280                 break;
281         }
282
283         g_array_free(in_param5, TRUE);
284
285         if (ret == NULL) {
286                 /* dBUS-RPC is failed */
287                 BT_ERR("dBUS-RPC is failed");
288
289                 if (error != NULL) {
290                         /* dBUS gives error cause */
291                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
292                                error->code, error->message);
293
294                         g_clear_error(&error);
295                 } else {
296                         /* dBUS does not give error cause dBUS-RPC is failed */
297                         BT_ERR("error returned was NULL");
298                 }
299
300                 return BLUETOOTH_ERROR_INTERNAL;
301         }
302
303         param1 = NULL;
304
305         g_variant_get(ret, "(iv)", &result, &param1);
306
307         if (param1) {
308                 *out_param1 = g_array_new(TRUE, TRUE, sizeof(gchar));
309                 _bt_core_fill_garray_from_variant(param1, *out_param1);
310                 g_variant_unref(param1);
311         }
312
313         g_variant_unref(ret);
314
315         return result;
316 }
317
318 static const gchar bt_core_introspection_xml[] =
319 "<node name='/'>"
320 "  <interface name='org.projectx.btcore'>"
321 "     <method name='EnableAdapter'>"
322 "     </method>"
323 "     <method name='DisableAdapter'>"
324 "     </method>"
325 "     <method name='RecoverAdapter'>"
326 "     </method>"
327 "     <method name='ResetAdapter'>"
328 "     </method>"
329 "     <method name='EnableAdapterLe'>"
330 "     </method>"
331 "     <method name='DisableAdapterLe'>"
332 "     </method>"
333 "     <method name='EnableCore'>"
334 "     </method>"
335 "         <method name='SetTransferValue'>"
336 "          <arg type='b' name='value' direction='in'/>"
337 "         </method>"
338 "     <method name='FactoryTestMode'>"
339 "          <arg type='s' name='type' direction='in'/>"
340 "          <arg type='s' name='arg' direction='in'/>"
341 "          <arg type='i' name='ret' direction='out'/>"
342 "     </method>"
343 " </interface>"
344 "</node>";
345
346 static guint obj_id, sig_id1, sig_id2, sig_id3;
347
348 static void __bt_core_dbus_method(GDBusConnection *connection,
349                         const gchar *sender,
350                         const gchar *object_path,
351                         const gchar *interface_name,
352                         const gchar *method_name,
353                         GVariant *parameters,
354                         GDBusMethodInvocation *invocation,
355                         gpointer user_data)
356 {
357         gboolean ret;
358
359         BT_DBG("method %s", method_name);
360
361         if (g_strcmp0(method_name, "EnableAdapter") == 0) {
362                 ret = _bt_core_enable_adapter();
363         } else if (g_strcmp0(method_name, "DisableAdapter") == 0) {
364                 ret = _bt_core_disable_adapter();
365         } else if (g_strcmp0(method_name, "RecoverAdapter") == 0) {
366                 ret = _bt_core_recover_adapter();
367         } else if (g_strcmp0(method_name, "ResetAdapter") == 0) {
368                 ret = __bt_core_reset_adapter();
369         } else if (g_strcmp0(method_name, "EnableAdapterLe") == 0) {
370                 ret = _bt_core_enable_adapter_le();
371         } else if (g_strcmp0(method_name, "DisableAdapterLe") == 0) {
372                 ret = _bt_core_disable_adapter_le();
373         } else if (g_strcmp0(method_name, "EnableCore") == 0) {
374                 ret = _bt_core_enable_core();
375         } else if (g_strcmp0(method_name, "SetTransferValue") == 0) {
376                 gboolean value = FALSE;
377
378                 g_variant_get(parameters, "(b)", &value);
379                 BT_DBG("Transfer value: %d", value);
380
381                 ret = _bt_core_set_transfer_value(value);
382         } else if (g_strcmp0(method_name, "FactoryTestMode") == 0) {
383                 const char *type = NULL;
384                 const char *arg = NULL;
385
386                 g_variant_get(parameters, "(&s&s)", &type, &arg);
387                 ret = _bt_core_factory_test_mode(type, arg);
388                 g_dbus_method_invocation_return_value(invocation,
389                                 g_variant_new("(i)", ret));
390                  return;
391         } else {
392                 ret = FALSE;
393         }
394
395         if (!ret) {
396                 GQuark quark = g_quark_from_string("bt-core");
397                 GError *err = g_error_new(quark, 0, "Failed");
398                 g_dbus_method_invocation_return_gerror(invocation, err);
399                 g_error_free(err);
400         } else {
401                 g_dbus_method_invocation_return_value(invocation, NULL);
402         }
403
404         BT_DBG("-");
405 }
406
407 static const GDBusInterfaceVTable method_table = {
408         __bt_core_dbus_method,
409         NULL,
410         NULL,
411 };
412
413 static GDBusNodeInfo *__bt_core_create_node_info(
414                                         const gchar *introspection_data)
415 {
416         GError *err = NULL;
417         GDBusNodeInfo *node_info = NULL;
418
419         if (introspection_data == NULL)
420                 return NULL;
421
422         node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
423
424         if (err) {
425                 BT_ERR("Unable to create node: %s", err->message);
426                 g_clear_error(&err);
427         }
428         return node_info;
429 }
430
431 gboolean __is_interface_and_signal_valid(const gchar *interface_name,
432                                                 const gchar *signal_name)
433 {
434         if (g_strcmp0(interface_name, "org.freedesktop.DBus") &&
435                 g_strcmp0(interface_name, "org.freedesktop.DBus.ObjectManager"))
436                 return FALSE;
437
438         if (g_strcmp0(signal_name, "NameOwnerChanged") &&
439                 g_strcmp0(signal_name, "InterfacesAdded") &&
440                 g_strcmp0(signal_name, "InterfacesRemoved"))
441                 return FALSE;
442
443         return TRUE;
444 }
445
446 static void __handle_name_owner_changed(const char *name)
447 {
448         gboolean flight_mode_status;
449
450         BT_DBG("");
451
452         flight_mode_status = _bt_core_is_flight_mode_enabled();
453
454         if (flight_mode_status == FALSE && _bt_is_flightmode_request() == TRUE) {
455                 BT_DBG("flightmode requested");
456                 return;
457         }
458
459         if ((g_strcmp0(name, "org.bluez") == 0) ||
460                 (g_strcmp0(name, "org.projectx.bt") == 0)) {
461                 BT_DBG("%s is terminated", name);
462                 if (_bt_check_terminating_condition() == TRUE) {
463                         _bt_disable_adapter();
464                         _bt_disable_adapter_le();
465                         _bt_core_terminate();
466                 }
467         }
468 }
469
470 static void __bt_core_event_filter(GDBusConnection *connection,
471                                                  const gchar *sender_name,
472                                                  const gchar *object_path,
473                                                  const gchar *interface_name,
474                                                  const gchar *signal_name,
475                                                  GVariant *parameters,
476                                                  gpointer user_data)
477 {
478         if (!__is_interface_and_signal_valid(interface_name, signal_name))
479                 return;
480
481         if (!g_strcmp0(signal_name, "InterfacesAdded")) {
482                 char *obj_path = NULL;
483                 GVariant *optional_param;
484
485                 g_variant_get(parameters, "(&o@a{sa{sv}})",
486                                                 &obj_path, &optional_param);
487
488                 if (g_strcmp0(obj_path, "/org/bluez/hci0") == 0)
489                         _bt_core_adapter_added_cb();
490
491         } else if (!g_strcmp0(signal_name, "InterfacesRemoved")) {
492                 char *obj_path = NULL;
493                 GVariant *optional_param;
494
495                 g_variant_get(parameters, "(&o@as)", &obj_path,
496                                                         &optional_param);
497
498                 if (g_strcmp0(obj_path, "/org/bluez/hci0") == 0)
499                         _bt_core_adapter_removed_cb();
500
501         } else { /* NameOwnerChanged */
502                 const char *name = NULL;
503                 const char *old_owner = NULL;
504                 const char *new_owner = NULL;
505
506                 g_variant_get(parameters, "(&s&s&s)", &name, &old_owner,
507                                                                 &new_owner);
508
509                 if (new_owner != NULL && *new_owner == '\0')
510                         __handle_name_owner_changed(name);
511         }
512 }
513
514 gboolean _bt_core_register_dbus(void)
515 {
516         GError *error = NULL;
517         guint owner_id;
518         GDBusNodeInfo *node_info;
519         gchar *path;
520         GDBusConnection *conn;
521
522         conn = _bt_core_get_gdbus_connection();
523         if (!conn)
524                 return FALSE;
525
526         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
527                                 BT_CORE_NAME,
528                                 G_BUS_NAME_OWNER_FLAGS_NONE,
529                                 NULL, NULL, NULL,
530                                 NULL, NULL);
531
532         BT_DBG("owner_id is [%d]", owner_id);
533
534         node_info = __bt_core_create_node_info(bt_core_introspection_xml);
535         if (node_info == NULL)
536                 return FALSE;
537
538         path = g_strdup(BT_CORE_PATH);
539         BT_DBG("path is [%s]", path);
540
541         obj_id = g_dbus_connection_register_object(conn, path,
542                                         node_info->interfaces[0],
543                                         &method_table,
544                                         NULL, NULL, &error);
545         g_dbus_node_info_unref(node_info);
546         if (obj_id == 0) {
547                 BT_ERR("Failed to register: %s", error->message);
548                 g_error_free(error);
549                 g_free(path);
550                 return FALSE;
551         }
552
553         g_free(path);
554
555         sig_id1 = g_dbus_connection_signal_subscribe(conn,
556                                 NULL, "org.freedesktop.DBus",
557                                 "NameOwnerChanged", NULL, NULL, 0,
558                                 __bt_core_event_filter, NULL, NULL);
559         sig_id2 = g_dbus_connection_signal_subscribe(conn,
560                                 NULL, "org.freedesktop.DBus.ObjectManager",
561                                 "InterfacesAdded", NULL, NULL,
562                                 0, __bt_core_event_filter, NULL, NULL);
563         sig_id2 = g_dbus_connection_signal_subscribe(conn,
564                                 NULL, "org.freedesktop.DBus.ObjectManager",
565                                 "InterfacesRemoved", NULL,
566                                 NULL, 0, __bt_core_event_filter, NULL, NULL);
567
568         return TRUE;
569 }
570
571 void  _bt_core_unregister_dbus(void)
572 {
573         GDBusConnection *conn;
574
575         BT_DBG("");
576
577         conn = _bt_core_get_gdbus_connection();
578         if (!conn)
579                 return;
580
581         if (obj_id > 0) {
582                 g_dbus_connection_unregister_object(conn, obj_id);
583                 obj_id = 0;
584         }
585
586         if (sig_id1 > 0) {
587                 g_dbus_connection_signal_unsubscribe(conn, sig_id1);
588                 sig_id1 = 0;
589         }
590         if (sig_id2 > 0) {
591                 g_dbus_connection_signal_unsubscribe(conn, sig_id2);
592                 sig_id2 = 0;
593         }
594         if (sig_id3 > 0) {
595                 g_dbus_connection_signal_unsubscribe(conn, sig_id3);
596                 sig_id3 = 0;
597         }
598 }