Merge branch 'master' into tizen_2.1
[platform/core/connectivity/bluetooth-frwk.git] / bt-core / bt_core.c
1 /*
2  * bluetooth-frwk
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <vconf.h>
24 #include <vconf-keys.h>
25
26 #include "bt_core.h"
27 #include "bt-internal-types.h"
28
29 static GMainLoop *main_loop = NULL;
30
31 typedef enum {
32         BT_DEACTIVATED,
33         BT_ACTIVATED,
34         BT_ACTIVATING,
35         BT_DEACTIVATING,
36 } bt_status_t;
37
38 static bt_status_t adapter_status = BT_DEACTIVATED;
39
40 static void __bt_core_terminate(void)
41 {
42         if (main_loop) {
43                 g_main_loop_quit(main_loop);
44         } else {
45                 BT_DBG("Terminating bt-core daemon");
46                 exit(0);
47         }
48 }
49
50 static void __bt_core_set_status(bt_status_t status)
51 {
52         adapter_status = status;
53 }
54
55 static bt_status_t __bt_core_get_status(void)
56 {
57         return adapter_status;
58 }
59
60 static gboolean bt_core_enable_adapter(BtCore *agent,
61                                                 DBusGMethodInvocation *context);
62
63 static gboolean bt_core_disable_adapter(BtCore *agent,
64                                                 DBusGMethodInvocation *context);
65
66 static gboolean bt_core_reset_adapter(BtCore *agent,
67                                                 DBusGMethodInvocation *context);
68
69 #include "bt_core_glue.h"
70
71 GType bt_core_get_type (void);
72
73
74 G_DEFINE_TYPE(BtCore, bt_core, G_TYPE_OBJECT);
75
76 /*This is part of platform provided code skeleton for client server model*/
77 static void bt_core_class_init (BtCoreClass *bt_core_class)
78 {
79         dbus_g_object_type_install_info(G_TYPE_FROM_CLASS(bt_core_class),
80                                         &dbus_glib_bt_core_object_info);
81 }
82
83 /*This is part of platform provided code skeleton for client server model*/
84 static void bt_core_init (BtCore *core)
85 {
86 }
87
88 typedef enum {
89         BT_CORE_ERROR_REJECT,
90         BT_CORE_ERROR_CANCEL,
91         BT_CORE_ERROR_TIMEOUT,
92 } BtCoreError;
93
94 #define BT_CORE_ERROR (bt_core_error_quark())
95
96 static GQuark bt_core_error_quark(void)
97 {
98         static GQuark quark = 0;
99         if (!quark)
100                 quark = g_quark_from_static_string("BtCore");
101
102         return quark;
103 }
104
105 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
106
107 static GError *bt_core_error(BtCoreError error, const char *err_msg)
108 {
109         return g_error_new(BT_CORE_ERROR, error, err_msg, NULL);
110 }
111
112 static int __bt_enable_adapter(void)
113 {
114         int ret;
115         bt_status_t status;
116
117         BT_DBG("");
118
119         status = __bt_core_get_status();
120         if (status != BT_DEACTIVATED) {
121                 BT_DBG("Invalid state %d", status);
122                 return -1;
123         }
124
125         __bt_core_set_status(BT_ACTIVATING);
126
127         ret = system("/usr/etc/bluetooth/bt-stack-up.sh &");
128         if (ret < 0) {
129                 BT_DBG("running script failed");
130                 ret = system("/usr/etc/bluetooth/bt-dev-end.sh &");
131                 __bt_core_set_status(BT_DEACTIVATED);
132                 return -1;
133         }
134
135         return 0;
136 }
137
138 static int __bt_disable_adapter(void)
139 {
140         bt_status_t status;
141
142         BT_DBG("");
143
144         status = __bt_core_get_status();
145         if (status == BT_ACTIVATING) {
146                 /* Forcely terminate */
147                 if (system("/usr/etc/bluetooth/bt-stack-down.sh &") < 0) {
148                         BT_DBG("running script failed");
149                 }
150                 __bt_core_terminate();
151                 return 0;
152         } else if (status != BT_ACTIVATED) {
153                 BT_DBG("Invalid state %d", status);
154                 return -1;
155         }
156
157         __bt_core_set_status(BT_DEACTIVATING);
158
159         if (system("/usr/etc/bluetooth/bt-stack-down.sh &") < 0) {
160                         BT_DBG("running script failed");
161                         __bt_core_set_status( BT_ACTIVATED);
162                         return -1;
163         }
164
165         return 0;
166 }
167
168 static gboolean bt_core_enable_adapter(BtCore *agent,
169                                                 DBusGMethodInvocation *context)
170 {
171         char *sender = dbus_g_method_get_sender(context);
172         int ret;
173
174         if (sender == NULL)
175                 return FALSE;
176
177         ret = __bt_enable_adapter();
178         if (ret < 0) {
179                 GError *error = bt_core_error(BT_CORE_ERROR_REJECT,
180                                                         "Activation failed");
181                 dbus_g_method_return_error(context, error);
182                 g_error_free(error);
183                 g_free(sender);
184                 return FALSE;
185         } else {
186                 dbus_g_method_return(context);
187         }
188
189         g_free(sender);
190         return TRUE;
191 }
192
193 static gboolean bt_core_disable_adapter(BtCore *agent,
194                                                 DBusGMethodInvocation *context)
195 {
196         char *sender = dbus_g_method_get_sender(context);
197         int ret;
198
199         if (sender == NULL)
200                 return FALSE;
201
202         ret = __bt_disable_adapter();
203         if (ret < 0) {
204                 GError *error = bt_core_error(BT_CORE_ERROR_REJECT,
205                                                         "Deactivation failed");
206                 dbus_g_method_return_error(context, error);
207                 g_error_free(error);
208                 g_free(sender);
209                 return FALSE;
210         } else {
211                 dbus_g_method_return(context);
212         }
213
214         g_free(sender);
215         return TRUE;
216 }
217
218 static int __bt_reset_adapter(void)
219 {
220         /* Forcely terminate */
221         if (system("/usr/etc/bluetooth/bt-reset-env.sh &") < 0) {
222                 BT_DBG("running script failed");
223         }
224         __bt_core_terminate();
225         return 0;
226 }
227
228 static gboolean bt_core_reset_adapter(BtCore *agent,
229                                                 DBusGMethodInvocation *context)
230 {
231         char *sender = dbus_g_method_get_sender(context);
232         int ret;
233
234         if (sender == NULL)
235                 return FALSE;
236
237         ret = __bt_reset_adapter();
238         if (ret < 0) {
239                 GError *error = bt_core_error(BT_CORE_ERROR_REJECT,
240                                                         "Deactivation failed");
241                 dbus_g_method_return_error(context, error);
242                 g_error_free(error);
243                 g_free(sender);
244                 return FALSE;
245         } else {
246                 dbus_g_method_return(context);
247         }
248
249         g_free(sender);
250         return TRUE;
251 }
252
253 static void __name_owner_changed(DBusGProxy *object, const char *name,
254                                         const char *prev, const char *new,
255                                                         gpointer user_data)
256 {
257         if (g_strcmp0(name, "org.bluez") == 0 && *new == '\0') {
258                 BT_DBG("BlueZ is terminated");
259                 __bt_disable_adapter();
260                 __bt_core_terminate();
261         } else if (g_strcmp0(name, "org.projectx.bt") == 0 && *new == '\0') {
262                 BT_DBG("bt-service is terminated abnormally");
263                 __bt_disable_adapter();
264         }
265 }
266
267 static DBusGProxy * __bt_core_register(DBusGConnection *conn, BtCore *bt_core)
268 {
269         DBusGProxy *proxy;
270         GError *err = NULL;
271         guint result = 0;
272
273         proxy = dbus_g_proxy_new_for_name(conn, DBUS_SERVICE_DBUS,
274                                 DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
275         if (proxy == NULL) {
276                 BT_ERR("proxy is NULL");
277                 return NULL;
278         }
279
280         if (!dbus_g_proxy_call(proxy, "RequestName", &err, G_TYPE_STRING,
281                         BT_CORE_NAME, G_TYPE_UINT, 0, G_TYPE_INVALID,
282                         G_TYPE_UINT, &result, G_TYPE_INVALID)) {
283                 if (err != NULL) {
284                         BT_ERR("RequestName RPC failed[%s]\n", err->message);
285                         g_error_free(err);
286                 }
287                 g_object_unref(proxy);
288                 return NULL;
289         }
290
291         if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
292                 BT_ERR("Failed to get the primary well-known name.\n");
293                 g_object_unref(proxy);
294                 return NULL;
295         }
296
297         dbus_g_proxy_add_signal(proxy, "NameOwnerChanged", G_TYPE_STRING,
298                                                 G_TYPE_STRING, G_TYPE_STRING,
299                                                 G_TYPE_INVALID);
300
301         dbus_g_proxy_connect_signal(proxy, "NameOwnerChanged",
302                                         G_CALLBACK(__name_owner_changed),
303                                         NULL, NULL);
304
305         dbus_g_connection_register_g_object(conn, BT_CORE_PATH,
306                                         G_OBJECT(bt_core));
307
308         return proxy;
309 }
310
311 static void __bt_core_unregister(DBusGConnection *conn, BtCore *bt_core,
312                                         DBusGProxy *dbus_proxy)
313 {
314         if (!bt_core || !dbus_proxy)
315                 return;
316
317         dbus_g_proxy_disconnect_signal(dbus_proxy, "NameOwnerChanged",
318                                                 G_CALLBACK(__name_owner_changed),
319                                                 NULL);
320
321         dbus_g_connection_unregister_g_object(conn, G_OBJECT(bt_core));
322
323         g_object_unref(bt_core);
324         g_object_unref(dbus_proxy);
325
326 }
327
328 static void __adapter_added_cb(DBusGProxy *manager_proxy,
329                                                 const char *adapter_path,
330                                                 gpointer user_data)
331 {
332         BT_DBG("");
333
334         __bt_core_set_status(BT_ACTIVATED);
335 }
336
337 static  void __adapter_removed_cb(DBusGProxy *manager_proxy,
338                                                 const char *adapter_path,
339                                                 gpointer user_data)
340 {
341         BT_DBG("");
342
343         __bt_core_set_status(BT_DEACTIVATED);
344
345         __bt_core_terminate();
346 }
347
348 static DBusGProxy *__bt_core_manager_init(DBusGConnection *conn)
349 {
350         DBusGProxy *manager_proxy;
351
352         manager_proxy = dbus_g_proxy_new_for_name(conn, "org.bluez", "/",
353                                                         "org.bluez.Manager");
354         if (manager_proxy == NULL) {
355                 BT_ERR("ERROR: Can't make manager proxy");
356                 return NULL;
357         }
358
359         dbus_g_proxy_add_signal(manager_proxy, "AdapterAdded",
360                                 DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
361         dbus_g_proxy_connect_signal(manager_proxy, "AdapterAdded",
362                                         G_CALLBACK(__adapter_added_cb),
363                                         NULL, NULL);
364
365         dbus_g_proxy_add_signal(manager_proxy, "AdapterRemoved",
366                                 DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
367         dbus_g_proxy_connect_signal(manager_proxy, "AdapterRemoved",
368                                         G_CALLBACK(__adapter_removed_cb),
369                                         NULL, NULL);
370
371         return manager_proxy;
372
373
374 }
375
376 static void __bt_core_manager_exit(DBusGProxy *manager_proxy)
377 {
378         if (!manager_proxy)
379                 return;
380
381         dbus_g_proxy_disconnect_signal(manager_proxy, "AdapterAdded",
382                                                 G_CALLBACK(__adapter_added_cb),
383                                                 NULL);
384
385         dbus_g_proxy_disconnect_signal(manager_proxy, "AdapterRemoved",
386                                         G_CALLBACK(__adapter_removed_cb),
387                                         NULL);
388
389         g_object_unref(manager_proxy);
390 }
391
392 static void __bt_core_sigterm_handler(int signo)
393 {
394         BT_DBG("Got the signal: %d", signo);
395
396         __bt_core_terminate();
397 }
398
399 int main(void)
400 {
401         DBusGConnection *conn = NULL;
402         GError *error = NULL;
403         BtCore *bt_core;
404         DBusGProxy *manager_proxy = NULL;
405         DBusGProxy *dbus_proxy = NULL;
406         struct sigaction sa;
407
408         BT_DBG("Starting bt-core daemeon");
409
410         g_type_init();
411
412         conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
413         if (error != NULL) {
414                 BT_ERR("ERROR: Can't get on system bus [%s]", error->message);
415                 g_error_free(error);
416                 return FALSE;
417         }
418
419         bt_core = g_object_new(BT_CORE_TYPE, NULL);
420
421         dbus_proxy = __bt_core_register(conn, bt_core);
422         if (!dbus_proxy) {
423                 BT_ERR("__bt_core_register failed");
424                 g_object_unref(bt_core);
425                 bt_core = NULL;
426                 goto fail;
427         }
428
429         manager_proxy = __bt_core_manager_init(conn);
430         if (!manager_proxy) {
431                 BT_ERR("__bt_core_manager_init failed");
432                 goto fail;
433         }
434
435         main_loop = g_main_loop_new(NULL, FALSE);
436
437         memset(&sa, 0, sizeof(sa));
438         sa.sa_handler = __bt_core_sigterm_handler;
439         sigaction(SIGINT, &sa, NULL);
440         sigaction(SIGTERM, &sa, NULL);
441
442         g_main_loop_run(main_loop);
443
444 fail:
445         __bt_core_unregister(conn, bt_core, dbus_proxy);
446
447          __bt_core_manager_exit(manager_proxy);
448
449         if (main_loop)
450                 g_main_loop_unref(main_loop);
451
452         dbus_g_connection_unref(conn);
453
454         BT_DBG("Terminating bt-core daemon");
455         return FALSE;
456 }