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