5208e719a1a19fb829ccd43239f742884c979de4
[platform/core/connectivity/bluetooth-frwk.git] / bt-core / bt-core-dbus-handler.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Hocheol Seo <hocheol.seo@samsung.com>
7  *               Girishashok Joshi <girish.joshi@samsung.com>
8  *               Chanyeol Park <chanyeol.park@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *              http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23
24 #include <gio/gio.h>
25 #include <vconf.h>
26 #include <vconf-keys.h>
27
28 #include "bt-core-adapter.h"
29 #include "bt-core-common.h"
30 #include "bt-core-dbus-handler.h"
31 #include "bt-internal-types.h"
32 #include "bt-request-service.h"
33 #include "bt-core-noti-handler.h"
34 #include "bt-core-main.h"
35
36 #define BT_SERVICE_NAME         "org.projectx.bt"
37 #define BT_SERVICE_PATH         "/org/projectx/bt_service"
38
39 DBusGProxy *service_proxy = NULL;
40 DBusGConnection *service_conn = NULL;
41
42 static GDBusConnection *service_gconn;
43 static GDBusProxy *service_gproxy;
44
45 void _bt_core_fill_garray_from_variant(GVariant *var, GArray *param)
46 {
47         char *data;
48         int size;
49
50         size = g_variant_get_size(var);
51         if (size > 0) {
52                 data = (char *)g_variant_get_data(var);
53                 if (data)
54                         param = g_array_append_vals(param, data, size);
55
56         }
57 }
58
59 static GDBusProxy *__bt_core_gdbus_init_service_proxy(void)
60 {
61         GDBusProxy *proxy;
62         GError *err = NULL;
63
64         g_type_init();
65
66         if (service_gconn == NULL)
67                 service_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
68
69         if (!service_gconn) {
70                 if (err) {
71                         BT_ERR("Unable to connect to dbus: %s", err->message);
72                         g_clear_error(&err);
73                 }
74                 return NULL;
75         }
76
77         proxy =  g_dbus_proxy_new_sync(service_gconn,
78                         G_DBUS_PROXY_FLAGS_NONE, NULL,
79                         BT_SERVICE_NAME,
80                         BT_SERVICE_PATH,
81                         BT_SERVICE_NAME,
82                         NULL, &err);
83         if (!proxy) {
84                 if (err) {
85                          BT_ERR("Unable to create proxy: %s", err->message);
86                          g_clear_error(&err);
87                 }
88
89                 g_object_unref(service_gconn);
90                 service_gconn = NULL;
91                 return NULL;
92         }
93
94         service_gproxy = proxy;
95
96         return proxy;
97 }
98
99 GDBusProxy *_bt_core_gdbus_get_service_proxy(void)
100 {
101         return (service_gproxy) ? service_gproxy : __bt_core_gdbus_init_service_proxy();
102 }
103
104 void _bt_core_gdbus_deinit_proxys(void)
105 {
106         if (service_gproxy) {
107                 g_object_unref(service_proxy);
108                 service_proxy = NULL;
109         }
110
111         if (service_gconn) {
112                 g_object_unref(service_gconn);
113                 service_gconn = NULL;
114         }
115 }
116
117 int _bt_core_service_request(int service_type, int service_function,
118                         GArray *in_param1, GArray *in_param2,
119                         GArray *in_param3, GArray *in_param4,
120                         GArray **out_param1)
121 {
122         GDBusProxy  *proxy;
123         GVariant *ret;
124         GVariant *param1;
125         GVariant *param2;
126         GVariant *param3;
127         GVariant *param4;
128         GVariant *param5;
129
130         int result = BLUETOOTH_ERROR_NONE;
131         GError *error = NULL;
132         GArray *in_param5 = NULL;
133         GArray *out_param2 = NULL;
134
135         proxy = _bt_core_gdbus_get_service_proxy();
136         if (!proxy)
137                 return BLUETOOTH_ERROR_INTERNAL;
138         in_param5 = g_array_new(TRUE, TRUE, sizeof(gchar));
139
140         param1 = g_variant_new_from_data((const GVariantType *)"ay",
141                                 in_param1->data, in_param1->len,
142                                 TRUE, NULL, NULL);
143         param2 = g_variant_new_from_data((const GVariantType *)"ay",
144                                 in_param2->data, in_param2->len,
145                                 TRUE, NULL, NULL);
146         param3 = g_variant_new_from_data((const GVariantType *)"ay",
147                                 in_param3->data, in_param3->len,
148                                 TRUE, NULL, NULL);
149         param4 = g_variant_new_from_data((const GVariantType *)"ay",
150                                 in_param4->data, in_param4->len,
151                                 TRUE, NULL, NULL);
152         param5 = g_variant_new_from_data((const GVariantType *)"ay",
153                                 in_param5->data, in_param5->len,
154                                 TRUE, NULL, NULL);
155
156         ret = g_dbus_proxy_call_sync(proxy, "service_request",
157                                 g_variant_new("(iii@ay@ay@ay@ay@ay)",
158                                         service_type, service_function,
159                                         BT_SYNC_REQ, param1,
160                                         param2, param3,
161                                         param4, param5),
162                                 G_DBUS_CALL_FLAGS_NONE, -1,
163                                 NULL, &error);
164
165         g_array_free(in_param5, TRUE);
166
167         if (ret == NULL) {
168                 /* dBUS-RPC is failed */
169                 BT_ERR("dBUS-RPC is failed");
170
171                 if (error != NULL) {
172                         /* dBUS gives error cause */
173                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]",
174                                error->code, error->message);
175
176                         g_clear_error(&error);
177                 } else {
178                         /* dBUS does not give error cause dBUS-RPC is failed */
179                         BT_ERR("error returned was NULL");
180                 }
181
182                 return BLUETOOTH_ERROR_INTERNAL;
183         }
184
185         param1 = NULL;
186         param2 = NULL;
187
188         g_variant_get(ret, "(@ay@ay)", &param1, &param2);
189
190         if (param1) {
191                 *out_param1 = g_array_new(TRUE, TRUE, sizeof(gchar));
192                 _bt_core_fill_garray_from_variant(param1, *out_param1);
193                 g_variant_unref(param1);
194         }
195
196         if (param2) {
197                 out_param2 = g_array_new(TRUE, TRUE, sizeof(gchar));
198                 _bt_core_fill_garray_from_variant(param2, out_param2);
199                 result = g_array_index(out_param2, int, 0);
200                 g_variant_unref(param2);
201                 g_array_free(out_param2, TRUE);
202         } else {
203                 result = BLUETOOTH_ERROR_INTERNAL;
204         }
205
206         g_variant_unref(ret);
207
208         return result;
209 }
210
211
212 static int __bt_core_get_object_path(DBusMessage *msg, char **path)
213 {
214         DBusMessageIter item_iter;
215
216         dbus_message_iter_init(msg, &item_iter);
217
218         if (dbus_message_iter_get_arg_type(&item_iter)
219                                         != DBUS_TYPE_OBJECT_PATH) {
220                 BT_ERR("This is bad format dbus");
221                 return BLUETOOTH_ERROR_INTERNAL;
222         }
223
224         dbus_message_iter_get_basic(&item_iter, path);
225
226         if (*path == NULL)
227                 return BLUETOOTH_ERROR_INTERNAL;
228
229         return BLUETOOTH_ERROR_NONE;
230 }
231
232 static int __bt_core_get_owner_info(DBusMessage *msg, char **name,
233                                 char **previous, char **current)
234 {
235         DBusMessageIter item_iter;
236
237         dbus_message_iter_init(msg, &item_iter);
238
239         if (dbus_message_iter_get_arg_type(&item_iter)
240                                         != DBUS_TYPE_STRING) {
241                 BT_ERR("This is bad format dbus");
242                 return BLUETOOTH_ERROR_INTERNAL;
243         }
244
245         dbus_message_iter_get_basic(&item_iter, name);
246
247         if (*name == NULL)
248                 return BLUETOOTH_ERROR_INTERNAL;
249
250         dbus_message_iter_next(&item_iter);
251
252         if (dbus_message_iter_get_arg_type(&item_iter)
253                                         != DBUS_TYPE_STRING) {
254                 BT_ERR("This is bad format dbus");
255                 return BLUETOOTH_ERROR_INTERNAL;
256         }
257
258         dbus_message_iter_get_basic(&item_iter, previous);
259
260         if (*previous == NULL)
261                 return BLUETOOTH_ERROR_INTERNAL;
262
263         dbus_message_iter_next(&item_iter);
264
265         if (dbus_message_iter_get_arg_type(&item_iter)
266                                         != DBUS_TYPE_STRING) {
267                 BT_ERR("This is bad format dbus");
268                 return BLUETOOTH_ERROR_INTERNAL;
269         }
270
271         dbus_message_iter_get_basic(&item_iter, current);
272
273         if (*current == NULL)
274                 return BLUETOOTH_ERROR_INTERNAL;
275
276         return BLUETOOTH_ERROR_NONE;
277 }
278
279 static DBusHandlerResult __bt_core_event_filter(DBusConnection *conn,
280                                            DBusMessage *msg, void *data)
281 {
282         char *object_path = NULL;
283         const char *member = dbus_message_get_member(msg);
284
285         if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
286                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
287
288         if (member == NULL)
289                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
290
291         if (strcasecmp(member, "InterfacesAdded") == 0) {
292                 if (__bt_core_get_object_path(msg, &object_path)) {
293                         BT_ERR("Fail to get the path");
294                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
295                 }
296
297                 if (strcasecmp(object_path, "/org/bluez/hci0") == 0) {
298                         _bt_core_adapter_added_cb();
299                 }
300         } else if (strcasecmp(member, "InterfacesRemoved") == 0) {
301                 if (__bt_core_get_object_path(msg, &object_path)) {
302                         BT_ERR("Fail to get the path");
303                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
304                 }
305
306                 if (strcasecmp(object_path, "/org/bluez/hci0") == 0) {
307 #ifdef __TIZEN_MOBILE__
308                 __bt_core_set_status(BT_DEACTIVATED);
309 #endif
310                         _bt_core_terminate();
311                 }
312         } else if (strcasecmp(member, "NameOwnerChanged") == 0) {
313                 char *name = NULL;
314                 char *previous = NULL;
315                 char *current = NULL;
316                 gboolean flight_mode_status;
317
318                 if (__bt_core_get_owner_info(msg, &name, &previous, &current)) {
319                         BT_ERR("Fail to get the owner info");
320                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
321                 }
322
323                 if (*current != '\0')
324                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
325
326                 if (vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &flight_mode_status) != 0)
327                         BT_ERR("Fail to get the flight_mode status value");
328                 if (flight_mode_status == FALSE && _bt_is_flightmode_request() == TRUE) {
329                         BT_DBG("flightmode requested");
330                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
331                 }
332
333                 if (strcasecmp(name, "org.bluez") == 0) {
334                         BT_DBG("Bluetoothd is terminated");
335                         if (_bt_check_terminating_condition() == TRUE) {
336                                 _bt_disable_adapter();
337                                 _bt_disable_adapter_le();
338                                 _bt_core_terminate();
339                         }
340                 } else if (strcasecmp(name, "org.projectx.bt") == 0) {
341                         BT_DBG("bt-service is terminated");
342                         if (_bt_check_terminating_condition() == TRUE) {
343                                 _bt_disable_adapter();
344                                 _bt_disable_adapter_le();
345                         }
346                 }
347         }
348
349         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
350 }
351
352 DBusGProxy *_bt_core_register_event_filter(DBusGConnection *g_conn,
353                                                 BtCore *bt_core)
354 {
355         DBusError dbus_error;
356         DBusConnection *conn;
357         DBusGProxy *proxy;
358         GError *err = NULL;
359         guint result = 0;
360
361         if (g_conn == NULL)
362                 return NULL;
363
364         conn = dbus_g_connection_get_connection(g_conn);
365         if (conn == NULL)
366                 return NULL;
367
368         proxy = dbus_g_proxy_new_for_name(g_conn, DBUS_SERVICE_DBUS,
369                                 DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
370         if (proxy == NULL) {
371                 BT_ERR("proxy is NULL");
372                 return NULL;
373         }
374
375         if (!dbus_g_proxy_call(proxy, "RequestName", &err, G_TYPE_STRING,
376                         BT_CORE_NAME, G_TYPE_UINT, 0, G_TYPE_INVALID,
377                         G_TYPE_UINT, &result, G_TYPE_INVALID)) {
378                 if (err != NULL) {
379                         BT_ERR("RequestName RPC failed[%s]\n", err->message);
380                         g_error_free(err);
381                 }
382                 g_object_unref(proxy);
383                 return NULL;
384         }
385
386         if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
387                 BT_ERR("Failed to get the primary well-known name.\n");
388                 g_object_unref(proxy);
389                 return NULL;
390         }
391
392         if (!dbus_connection_add_filter(conn, __bt_core_event_filter,
393                                         NULL, NULL)) {
394                 BT_ERR("Fail to add filter");
395                 g_object_unref(proxy);
396                 return NULL;
397         }
398
399         dbus_error_init(&dbus_error);
400
401         dbus_bus_add_match(conn,
402                         "type='signal',interface='org.freedesktop.DBus'"
403                         ",member='NameOwnerChanged'",
404                         &dbus_error);
405
406         if (dbus_error_is_set(&dbus_error)) {
407                 BT_ERR("Fail to add match: %s\n", dbus_error.message);
408                 dbus_error_free(&dbus_error);
409                 g_object_unref(proxy);
410                 return NULL;
411         }
412
413         dbus_bus_add_match(conn,
414                         "type='signal',interface='org.freedesktop.DBus.ObjectManager'"
415                         ",member='InterfacesAdded'",
416                         &dbus_error);
417
418         if (dbus_error_is_set(&dbus_error)) {
419                 BT_ERR("Fail to add match: %s\n", dbus_error.message);
420                 dbus_error_free(&dbus_error);
421                 g_object_unref(proxy);
422                 return NULL;
423         }
424
425         dbus_bus_add_match(conn,
426                         "type='signal',interface='org.freedesktop.DBus.ObjectManager'"
427                         ",member='InterfacesRemoved'",
428                         &dbus_error);
429
430         if (dbus_error_is_set(&dbus_error)) {
431                 BT_ERR("Fail to add match: %s\n", dbus_error.message);
432                 dbus_error_free(&dbus_error);
433                 g_object_unref(proxy);
434                 return NULL;
435         }
436
437         dbus_g_connection_register_g_object(g_conn, BT_CORE_PATH,
438                                         G_OBJECT(bt_core));
439
440         return proxy;
441 }
442
443 void _bt_unregister_event_filter(DBusGConnection *g_conn,
444                                         BtCore *bt_core,
445                                         DBusGProxy *dbus_proxy)
446 {
447         DBusConnection *conn;
448
449         if (g_conn == NULL ||
450              bt_core == NULL ||
451               dbus_proxy == NULL) {
452                 BT_ERR("Invalid parameter");
453                 return;
454         }
455
456         conn = dbus_g_connection_get_connection(g_conn);
457
458         dbus_connection_remove_filter(conn, __bt_core_event_filter, NULL);
459
460         dbus_g_connection_unregister_g_object(g_conn, G_OBJECT(bt_core));
461
462         g_object_unref(bt_core);
463         g_object_unref(dbus_proxy);
464 }
465