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