[Boiler Plate] Update Boiler plate to remove unwanted information
[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 HPS_FEATURE
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 HPS_FEATURE
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         g_type_init();
83
84         conn = _bt_core_get_gdbus_connection();
85         if (!conn)
86                 return NULL;
87
88         proxy =  g_dbus_proxy_new_sync(conn,
89                         G_DBUS_PROXY_FLAGS_NONE, NULL,
90                         BT_SERVICE_NAME,
91                         BT_SERVICE_PATH,
92                         BT_SERVICE_NAME,
93                         NULL, &err);
94         if (!proxy) {
95                 if (err) {
96                          BT_ERR("Unable to create proxy: %s", err->message);
97                          g_clear_error(&err);
98                 }
99
100                 return NULL;
101         }
102
103         service_gproxy = proxy;
104
105         return proxy;
106 }
107
108 GDBusProxy *_bt_core_gdbus_get_service_proxy(void)
109 {
110         return (service_gproxy) ? service_gproxy : __bt_core_gdbus_init_service_proxy();
111 }
112
113 #ifdef HPS_FEATURE
114 int _bt_core_start_httpproxy(void)
115 {
116         GVariant *variant = NULL;
117         unsigned char enabled;
118
119         BT_DBG(" ");
120
121         hps_gproxy = _bt_core_gdbus_get_hps_proxy();
122         if (!hps_gproxy) {
123                 BT_DBG("Couldn't get service proxy");
124                 return -1;
125         }
126
127         variant = g_dbus_proxy_call_sync(hps_gproxy, "enable",
128                                 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
129         if (variant) {
130                 g_variant_get(variant, "(y)", &enabled);
131                 BT_ERR("HPS enabled status 0x%x", enabled);
132         }
133         return 0;
134 }
135
136 int _bt_core_stop_httpproxy(void)
137 {
138         GVariant *variant = NULL;
139         unsigned char enabled;
140
141         BT_DBG(" ");
142
143         hps_gproxy = _bt_core_gdbus_get_hps_proxy();
144         if (!hps_gproxy) {
145                 BT_DBG("Couldn't get service proxy");
146                 return -1;
147         }
148
149         variant = g_dbus_proxy_call_sync(hps_gproxy, "disable",
150                                 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
151         if (variant) {
152                 g_variant_get(variant, "(y)", &enabled);
153                 BT_ERR("HPS disabled status 0x%x", enabled);
154         }
155         return 0;
156 }
157
158 static GDBusProxy *_bt_core_gdbus_init_hps_proxy(void)
159 {
160         GDBusProxy *proxy;
161         GError *err = NULL;
162         GDBusConnection *conn;
163
164         g_type_init();
165
166         BT_DBG(" ");
167
168         conn = _bt_core_get_gdbus_connection();
169         if (!conn)
170                 return NULL;
171
172         proxy =  g_dbus_proxy_new_sync(conn,
173                         G_DBUS_PROXY_FLAGS_NONE, NULL,
174                         BT_HPS_SERVICE_NAME,
175                         BT_HPS_OBJECT_PATH,
176                         BT_HPS_INTERFACE_NAME,
177                         NULL, &err);
178         if (proxy == NULL) {
179                 if (err) {
180                          BT_ERR("Unable to create proxy: %s", err->message);
181                          g_clear_error(&err);
182                 }
183                 return NULL;
184         }
185
186         hps_gproxy = proxy;
187
188         return proxy;
189 }
190
191 GDBusProxy *_bt_core_gdbus_get_hps_proxy(void)
192 {
193         return (hps_gproxy) ? hps_gproxy : _bt_core_gdbus_init_hps_proxy();
194 }
195 #endif
196
197 void _bt_core_gdbus_deinit_proxys(void)
198 {
199         BT_DBG("");
200
201         if (service_gproxy) {
202                 g_object_unref(service_gproxy);
203                 service_gproxy = NULL;
204         }
205
206 #ifdef HPS_FEATURE
207         if (hps_gproxy) {
208                 g_object_unref(hps_gproxy);
209                 hps_gproxy = NULL;
210         }
211 #endif
212
213         if (service_gconn) {
214                 g_object_unref(service_gconn);
215                 service_gconn = NULL;
216         }
217 }
218
219 int _bt_core_service_request(int service_type, int service_function,
220                         GArray *in_param1, GArray *in_param2,
221                         GArray *in_param3, GArray *in_param4,
222                         GArray **out_param1)
223 {
224         GDBusProxy  *proxy;
225         GVariant *ret;
226         GVariant *param1;
227         GVariant *param2;
228         GVariant *param3;
229         GVariant *param4;
230         GVariant *param5;
231
232         int result = BLUETOOTH_ERROR_NONE;
233         GError *error = NULL;
234         GArray *in_param5 = NULL;
235
236         int retry = 5;
237
238         proxy = _bt_core_gdbus_get_service_proxy();
239         if (!proxy)
240                 return BLUETOOTH_ERROR_INTERNAL;
241         in_param5 = g_array_new(TRUE, TRUE, sizeof(gchar));
242
243         while (--retry >= 0) {
244                 param1 = g_variant_new_from_data((const GVariantType *)"ay",
245                                         in_param1->data, in_param1->len,
246                                         TRUE, NULL, NULL);
247                 param2 = g_variant_new_from_data((const GVariantType *)"ay",
248                                         in_param2->data, in_param2->len,
249                                         TRUE, NULL, NULL);
250                 param3 = g_variant_new_from_data((const GVariantType *)"ay",
251                                         in_param3->data, in_param3->len,
252                                         TRUE, NULL, NULL);
253                 param4 = g_variant_new_from_data((const GVariantType *)"ay",
254                                         in_param4->data, in_param4->len,
255                                         TRUE, NULL, NULL);
256                 param5 = g_variant_new_from_data((const GVariantType *)"ay",
257                                         in_param5->data, in_param5->len,
258                                         TRUE, NULL, NULL);
259
260                 ret = g_dbus_proxy_call_sync(proxy, "service_request",
261                                         g_variant_new("(iii@ay@ay@ay@ay@ay)",
262                                                 service_type, service_function,
263                                                 BT_SYNC_REQ, param1,
264                                                 param2, param3,
265                                                 param4, param5),
266                                         G_DBUS_CALL_FLAGS_NONE, 2000,
267                                         NULL, &error);
268                 if (ret == NULL && error != NULL) {
269                         if (error->code == G_IO_ERROR_TIMED_OUT) {
270                                 BT_ERR("D-Bus Timed out.");
271                                 g_clear_error(&error);
272                                 continue;
273                         }
274                 }
275
276                 break;
277         }
278
279         g_array_free(in_param5, TRUE);
280
281         if (ret == NULL) {
282                 /* dBUS-RPC is failed */
283                 BT_ERR("dBUS-RPC is failed");
284
285                 if (error != NULL) {
286                         /* dBUS gives error cause */
287                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
288                                error->code, error->message);
289
290                         g_clear_error(&error);
291                 } else {
292                         /* dBUS does not give error cause dBUS-RPC is failed */
293                         BT_ERR("error returned was NULL");
294                 }
295
296                 return BLUETOOTH_ERROR_INTERNAL;
297         }
298
299         param1 = NULL;
300
301         g_variant_get(ret, "(iv)", &result, &param1);
302
303         if (param1) {
304                 *out_param1 = g_array_new(TRUE, TRUE, sizeof(gchar));
305                 _bt_core_fill_garray_from_variant(param1, *out_param1);
306                 g_variant_unref(param1);
307         }
308
309         g_variant_unref(ret);
310
311         return result;
312 }
313
314 static const gchar bt_core_introspection_xml[] =
315 "<node name='/'>"
316 "  <interface name='org.projectx.btcore'>"
317 "     <method name='EnableAdapter'>"
318 "     </method>"
319 "     <method name='DisableAdapter'>"
320 "     </method>"
321 "     <method name='RecoverAdapter'>"
322 "     </method>"
323 "     <method name='ResetAdapter'>"
324 "     </method>"
325 "     <method name='EnableAdapterLe'>"
326 "     </method>"
327 "     <method name='DisableAdapterLe'>"
328 "     </method>"
329 "     <method name='EnableCore'>"
330 "     </method>"
331 "     <method name='FactoryTestMode'>"
332 "          <arg type='s' name='type' direction='in'/>"
333 "          <arg type='s' name='arg' direction='in'/>"
334 "          <arg type='i' name='ret' direction='out'/>"
335 "     </method>"
336 " </interface>"
337 "</node>";
338
339 static guint obj_id, sig_id1, sig_id2, sig_id3;
340
341 static void __bt_core_dbus_method(GDBusConnection *connection,
342                         const gchar *sender,
343                         const gchar *object_path,
344                         const gchar *interface_name,
345                         const gchar *method_name,
346                         GVariant *parameters,
347                         GDBusMethodInvocation *invocation,
348                         gpointer user_data)
349 {
350         gboolean ret;
351
352         BT_DBG("method %s", method_name);
353
354         if (g_strcmp0(method_name, "EnableAdapter") == 0) {
355                 ret = _bt_core_enable_adapter();
356         } else if (g_strcmp0(method_name, "DisableAdapter") == 0) {
357                 ret = _bt_core_disable_adapter();
358         } else if (g_strcmp0(method_name, "RecoverAdapter") == 0) {
359                 ret = _bt_core_recover_adapter();
360         } else if (g_strcmp0(method_name, "ResetAdapter") == 0) {
361                 ret = __bt_core_reset_adapter();
362         } else if (g_strcmp0(method_name, "EnableAdapterLe") == 0) {
363                 ret = _bt_core_enable_adapter_le();
364         } else if (g_strcmp0(method_name, "DisableAdapterLe") == 0) {
365                 ret = _bt_core_disable_adapter_le();
366         } else if (g_strcmp0(method_name, "EnableCore") == 0) {
367                 ret = _bt_core_enable_core();
368         } else if (g_strcmp0(method_name, "FactoryTestMode") == 0) {
369                 const char *type = NULL;
370                 const char *arg = NULL;
371
372                 g_variant_get(parameters, "(&s&s)", &type, &arg);
373                 ret = _bt_core_factory_test_mode(type, arg);
374                 g_dbus_method_invocation_return_value(invocation,
375                                 g_variant_new("(i)", ret));
376                  return;
377         } else {
378                 ret = FALSE;
379         }
380
381         if (!ret) {
382                 GQuark quark = g_quark_from_string("bt-core");
383                 GError *err = g_error_new(quark, 0, "Failed");
384                 g_dbus_method_invocation_return_gerror(invocation, err);
385                 g_error_free(err);
386         } else {
387                 g_dbus_method_invocation_return_value(invocation, NULL);
388         }
389
390         BT_DBG("-");
391 }
392
393 static const GDBusInterfaceVTable method_table = {
394         __bt_core_dbus_method,
395         NULL,
396         NULL,
397 };
398
399 static GDBusNodeInfo *__bt_core_create_node_info(
400                                         const gchar *introspection_data)
401 {
402         GError *err = NULL;
403         GDBusNodeInfo *node_info = NULL;
404
405         if (introspection_data == NULL)
406                 return NULL;
407
408         node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
409
410         if (err) {
411                 BT_ERR("Unable to create node: %s", err->message);
412                 g_clear_error(&err);
413         }
414         return node_info;
415 }
416
417 gboolean __is_interface_and_signal_valid(const gchar *interface_name,
418                                                 const gchar *signal_name)
419 {
420         if (g_strcmp0(interface_name, "org.freedesktop.DBus") &&
421                 g_strcmp0(interface_name, "org.freedesktop.DBus.ObjectManager"))
422                 return FALSE;
423
424         if (g_strcmp0(signal_name, "NameOwnerChanged") &&
425                 g_strcmp0(signal_name, "InterfacesAdded") &&
426                 g_strcmp0(signal_name, "InterfacesRemoved"))
427                 return FALSE;
428
429         return TRUE;
430 }
431
432 static void __handle_name_owner_changed(const char *name)
433 {
434         gboolean flight_mode_status;
435
436         BT_DBG("");
437
438         flight_mode_status = _bt_core_is_flight_mode_enabled();
439
440         if (flight_mode_status == FALSE && _bt_is_flightmode_request() == TRUE) {
441                 BT_DBG("flightmode requested");
442                 return;
443         }
444
445         if ((g_strcmp0(name, "org.bluez") == 0) ||
446                 (g_strcmp0(name, "org.projectx.bt") == 0)) {
447                 BT_DBG("%s is terminated", name);
448                 if (_bt_check_terminating_condition() == TRUE) {
449                         _bt_disable_adapter();
450                         _bt_disable_adapter_le();
451                         _bt_core_terminate();
452                 }
453         }
454 }
455
456 static void __bt_core_event_filter(GDBusConnection *connection,
457                                                  const gchar *sender_name,
458                                                  const gchar *object_path,
459                                                  const gchar *interface_name,
460                                                  const gchar *signal_name,
461                                                  GVariant *parameters,
462                                                  gpointer user_data)
463 {
464         if (!__is_interface_and_signal_valid(interface_name, signal_name))
465                 return;
466
467         if (!g_strcmp0(signal_name, "InterfacesAdded")) {
468                 char *obj_path = NULL;
469                 GVariant *optional_param;
470
471                 g_variant_get(parameters, "(&o@a{sa{sv}})",
472                                                 &obj_path, &optional_param);
473
474                 if (g_strcmp0(obj_path, "/org/bluez/hci0") == 0) {
475                         _bt_core_adapter_added_cb();
476                 }
477         } else if (!g_strcmp0(signal_name, "InterfacesRemoved")) {
478                 char *obj_path = NULL;
479                 GVariant *optional_param;
480
481                 g_variant_get(parameters, "(&o@as)", &obj_path,
482                                                         &optional_param);
483
484                 if (g_strcmp0(obj_path, "/org/bluez/hci0") == 0) {
485                         _bt_core_adapter_removed_cb();
486                 }
487         } else { /* NameOwnerChanged */
488                 const char *name = NULL;
489                 const char *old_owner = NULL;
490                 const char *new_owner = NULL;
491
492                 g_variant_get(parameters, "(&s&s&s)", &name, &old_owner,
493                                                                 &new_owner);
494
495                 if (new_owner != NULL && *new_owner == '\0')
496                         __handle_name_owner_changed(name);
497         }
498 }
499
500 gboolean _bt_core_register_dbus(void)
501 {
502         GError *error = NULL;
503         guint owner_id;
504         GDBusNodeInfo *node_info;
505         gchar *path;
506         GDBusConnection *conn;
507
508         conn = _bt_core_get_gdbus_connection();
509         if (!conn)
510                 return FALSE;
511
512         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
513                                 BT_CORE_NAME,
514                                 G_BUS_NAME_OWNER_FLAGS_NONE,
515                                 NULL, NULL, NULL,
516                                 NULL, NULL);
517
518         BT_DBG("owner_id is [%d]", owner_id);
519
520         node_info = __bt_core_create_node_info(bt_core_introspection_xml);
521         if (node_info == NULL)
522                 return FALSE;
523
524         path = g_strdup(BT_CORE_PATH);
525         BT_DBG("path is [%s]", path);
526
527         obj_id = g_dbus_connection_register_object(conn, path,
528                                         node_info->interfaces[0],
529                                         &method_table,
530                                         NULL, NULL, &error);
531         if (obj_id == 0) {
532                 BT_ERR("Failed to register: %s", error->message);
533                 g_error_free(error);
534                 g_free(path);
535                 return FALSE;
536         }
537
538         g_free(path);
539
540         sig_id1 = g_dbus_connection_signal_subscribe(conn,
541                                 NULL, "org.freedesktop.DBus",
542                                 "NameOwnerChanged", NULL, NULL, 0,
543                                 __bt_core_event_filter, NULL, NULL);
544         sig_id2 = g_dbus_connection_signal_subscribe(conn,
545                                 NULL, "org.freedesktop.DBus.ObjectManager",
546                                 "InterfacesAdded", NULL, NULL,
547                                 0, __bt_core_event_filter, NULL, NULL);
548         sig_id2 = g_dbus_connection_signal_subscribe(conn,
549                                 NULL, "org.freedesktop.DBus.ObjectManager",
550                                 "InterfacesRemoved", NULL,
551                                 NULL, 0, __bt_core_event_filter, NULL, NULL);
552
553         return TRUE;
554 }
555
556 void  _bt_core_unregister_dbus(void)
557 {
558         GDBusConnection *conn;
559
560         BT_DBG("");
561
562         conn = _bt_core_get_gdbus_connection();
563         if (!conn)
564                 return;
565
566         if (obj_id > 0) {
567                 g_dbus_connection_unregister_object(conn, obj_id);
568                 obj_id = 0;
569         }
570
571         if (sig_id1 > 0) {
572                 g_dbus_connection_signal_unsubscribe(conn, sig_id1);
573                 sig_id1 = 0;
574         }
575         if (sig_id2 > 0) {
576                 g_dbus_connection_signal_unsubscribe(conn, sig_id2);
577                 sig_id2 = 0;
578         }
579         if (sig_id3 > 0) {
580                 g_dbus_connection_signal_unsubscribe(conn, sig_id3);
581                 sig_id3 = 0;
582         }
583 }