tizen 2.3.1 release
[framework/connectivity/bluez.git] / src / main.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2000-2001  Qualcomm Incorporated
6  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
8  *
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <errno.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <signal.h>
36 #include <stdbool.h>
37 #include <sys/signalfd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40
41 #include <glib.h>
42
43 #include <dbus/dbus.h>
44
45 #include "lib/bluetooth.h"
46 #include "lib/sdp.h"
47
48 #include "gdbus/gdbus.h"
49
50 #include "log.h"
51
52 #include "lib/uuid.h"
53 #include "hcid.h"
54 #include "sdpd.h"
55 #include "adapter.h"
56 #include "device.h"
57 #include "dbus-common.h"
58 #include "agent.h"
59 #include "profile.h"
60 #include "systemd.h"
61
62 #ifdef __TIZEN_PATCH__
63 #include "gatt.h"
64 #endif
65
66 #define BLUEZ_NAME "org.bluez"
67
68 #define DEFAULT_PAIRABLE_TIMEOUT       0 /* disabled */
69 #define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
70
71 #define SHUTDOWN_GRACE_SECONDS 10
72
73 struct main_opts main_opts;
74 static GKeyFile *main_conf;
75
76 static enum {
77         MPS_OFF,
78         MPS_SINGLE,
79         MPS_MULTIPLE,
80 } mps = MPS_OFF;
81
82 static const char * const supported_options[] = {
83         "Name",
84         "Class",
85         "DiscoverableTimeout",
86         "AlwaysPairable",
87         "PairableTimeout",
88         "AutoConnectTimeout",
89         "DeviceID",
90         "ReverseServiceDiscovery",
91         "NameResolving",
92         "DebugKeys",
93         "ControllerMode",
94         "MultiProfile",
95 #ifdef __TIZEN_PATCH__
96         "EnableLEPrivacy",
97 #endif
98 };
99
100 GKeyFile *btd_get_main_conf(void)
101 {
102         return main_conf;
103 }
104
105 static GKeyFile *load_config(const char *file)
106 {
107         GError *err = NULL;
108         GKeyFile *keyfile;
109
110         keyfile = g_key_file_new();
111
112         g_key_file_set_list_separator(keyfile, ',');
113
114         if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
115                 if (!g_error_matches(err, G_FILE_ERROR, G_FILE_ERROR_NOENT))
116                         error("Parsing %s failed: %s", file, err->message);
117                 g_error_free(err);
118                 g_key_file_free(keyfile);
119                 return NULL;
120         }
121
122         return keyfile;
123 }
124
125 static void parse_did(const char *did)
126 {
127         int result;
128         uint16_t vendor, product, version , source;
129
130         /* version and source are optional */
131         version = 0x0000;
132         source = 0x0002;
133
134         result = sscanf(did, "bluetooth:%4hx:%4hx:%4hx",
135                                         &vendor, &product, &version);
136         if (result != EOF && result >= 2) {
137                 source = 0x0001;
138                 goto done;
139         }
140
141         result = sscanf(did, "usb:%4hx:%4hx:%4hx",
142                                         &vendor, &product, &version);
143         if (result != EOF && result >= 2)
144                 goto done;
145
146         result = sscanf(did, "%4hx:%4hx:%4hx", &vendor, &product, &version);
147         if (result == EOF || result < 2)
148                 return;
149
150 done:
151         main_opts.did_source = source;
152         main_opts.did_vendor = vendor;
153         main_opts.did_product = product;
154         main_opts.did_version = version;
155 }
156
157 static void check_config(GKeyFile *config)
158 {
159         const char *valid_groups[] = { "General", "Policy", NULL };
160         char **keys;
161         int i;
162
163         if (!config)
164                 return;
165
166         keys = g_key_file_get_groups(config, NULL);
167
168         for (i = 0; keys != NULL && keys[i] != NULL; i++) {
169                 const char **group;
170                 bool match = false;
171
172                 for (group = valid_groups; *group; group++) {
173                         if (g_str_equal(keys[i], *group)) {
174                                 match = true;
175                                 break;
176                         }
177                 }
178
179                 if (!match)
180                         warn("Unknown group %s in main.conf", keys[i]);
181         }
182
183         g_strfreev(keys);
184
185         keys = g_key_file_get_keys(config, "General", NULL, NULL);
186
187         for (i = 0; keys != NULL && keys[i] != NULL; i++) {
188                 bool found;
189                 unsigned int j;
190
191                 found = false;
192                 for (j = 0; j < G_N_ELEMENTS(supported_options); j++) {
193                         if (g_str_equal(keys[i], supported_options[j])) {
194                                 found = true;
195                                 break;
196                         }
197                 }
198
199                 if (!found)
200                         warn("Unknown key %s in main.conf", keys[i]);
201         }
202
203         g_strfreev(keys);
204 }
205
206 static int get_mode(const char *str)
207 {
208         if (strcmp(str, "dual") == 0)
209                 return BT_MODE_DUAL;
210         else if (strcmp(str, "bredr") == 0)
211                 return BT_MODE_BREDR;
212         else if (strcmp(str, "le") == 0)
213                 return BT_MODE_LE;
214
215         error("Unknown controller mode \"%s\"", str);
216
217         return BT_MODE_DUAL;
218 }
219
220 static void parse_config(GKeyFile *config)
221 {
222         GError *err = NULL;
223         char *str;
224         int val;
225         gboolean boolean;
226
227         if (!config)
228                 return;
229
230         check_config(config);
231
232         DBG("parsing main.conf");
233
234         val = g_key_file_get_integer(config, "General",
235                                                 "DiscoverableTimeout", &err);
236         if (err) {
237                 DBG("%s", err->message);
238                 g_clear_error(&err);
239         } else {
240                 DBG("discovto=%d", val);
241                 main_opts.discovto = val;
242         }
243
244         val = g_key_file_get_integer(config, "General",
245                                                 "PairableTimeout", &err);
246         if (err) {
247                 DBG("%s", err->message);
248                 g_clear_error(&err);
249         } else {
250                 DBG("pairto=%d", val);
251                 main_opts.pairto = val;
252         }
253
254         val = g_key_file_get_integer(config, "General", "AutoConnectTimeout",
255                                                                         &err);
256         if (err) {
257                 DBG("%s", err->message);
258                 g_clear_error(&err);
259         } else {
260                 DBG("auto_to=%d", val);
261                 main_opts.autoto = val;
262         }
263
264         str = g_key_file_get_string(config, "General", "Name", &err);
265         if (err) {
266                 DBG("%s", err->message);
267                 g_clear_error(&err);
268         } else {
269                 DBG("name=%s", str);
270                 g_free(main_opts.name);
271                 main_opts.name = str;
272         }
273
274         str = g_key_file_get_string(config, "General", "Class", &err);
275         if (err) {
276                 DBG("%s", err->message);
277                 g_clear_error(&err);
278         } else {
279                 DBG("class=%s", str);
280                 main_opts.class = strtol(str, NULL, 16);
281                 g_free(str);
282         }
283
284         str = g_key_file_get_string(config, "General", "DeviceID", &err);
285         if (err) {
286                 DBG("%s", err->message);
287                 g_clear_error(&err);
288         } else {
289                 DBG("deviceid=%s", str);
290                 parse_did(str);
291                 g_free(str);
292         }
293
294         boolean = g_key_file_get_boolean(config, "General",
295                                                 "ReverseServiceDiscovery", &err);
296         if (err) {
297                 DBG("%s", err->message);
298                 g_clear_error(&err);
299         } else
300                 main_opts.reverse_sdp = boolean;
301
302         boolean = g_key_file_get_boolean(config, "General",
303                                                 "NameResolving", &err);
304         if (err)
305                 g_clear_error(&err);
306         else
307                 main_opts.name_resolv = boolean;
308
309         boolean = g_key_file_get_boolean(config, "General",
310                                                 "DebugKeys", &err);
311         if (err)
312                 g_clear_error(&err);
313         else
314                 main_opts.debug_keys = boolean;
315
316         str = g_key_file_get_string(config, "General", "ControllerMode", &err);
317         if (err) {
318                 g_clear_error(&err);
319         } else {
320                 DBG("ControllerMode=%s", str);
321                 main_opts.mode = get_mode(str);
322                 g_free(str);
323         }
324
325         str = g_key_file_get_string(config, "General", "MultiProfile", &err);
326         if (err) {
327                 g_clear_error(&err);
328         } else {
329                 DBG("MultiProfile=%s", str);
330
331                 if (!strcmp(str, "single"))
332                         mps = MPS_SINGLE;
333                 else if (!strcmp(str, "multiple"))
334                         mps = MPS_MULTIPLE;
335
336                 g_free(str);
337         }
338 #ifdef __TIZEN_PATCH__
339         boolean = g_key_file_get_boolean(config, "General",
340                                                 "EnableLEPrivacy", &err);
341         if (err)
342                 g_clear_error(&err);
343         else
344                 main_opts.le_privacy = boolean;
345 #endif
346 }
347
348 static void init_defaults(void)
349 {
350         uint8_t major, minor;
351
352         /* Default HCId settings */
353         memset(&main_opts, 0, sizeof(main_opts));
354         main_opts.name = g_strdup_printf("BlueZ %s", VERSION);
355         main_opts.class = 0x000000;
356         main_opts.pairto = DEFAULT_PAIRABLE_TIMEOUT;
357         main_opts.discovto = DEFAULT_DISCOVERABLE_TIMEOUT;
358         main_opts.reverse_sdp = TRUE;
359         main_opts.name_resolv = TRUE;
360         main_opts.debug_keys = FALSE;
361 #ifdef __TIZEN_PATCH__
362         main_opts.le_privacy = FALSE;
363 #endif
364
365         if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
366                 return;
367
368         main_opts.did_source = 0x0002;          /* USB */
369         main_opts.did_vendor = 0x1d6b;          /* Linux Foundation */
370         main_opts.did_product = 0x0246;         /* BlueZ */
371         main_opts.did_version = (major << 8 | minor);
372 }
373
374 static GMainLoop *event_loop;
375
376 void btd_exit(void)
377 {
378         g_main_loop_quit(event_loop);
379 }
380
381 static gboolean quit_eventloop(gpointer user_data)
382 {
383         btd_exit();
384         return FALSE;
385 }
386
387 static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
388                                                         gpointer user_data)
389 {
390         static unsigned int __terminated = 0;
391         struct signalfd_siginfo si;
392         ssize_t result;
393         int fd;
394
395         if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
396                 return FALSE;
397
398         fd = g_io_channel_unix_get_fd(channel);
399
400         result = read(fd, &si, sizeof(si));
401         if (result != sizeof(si))
402                 return FALSE;
403
404         switch (si.ssi_signo) {
405         case SIGINT:
406         case SIGTERM:
407                 if (__terminated == 0) {
408                         info("Terminating");
409                         g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
410                                                         quit_eventloop, NULL);
411
412                         sd_notify(0, "STATUS=Powering down");
413                         adapter_shutdown();
414                 }
415
416                 __terminated = 1;
417                 break;
418         case SIGUSR2:
419                 __btd_toggle_debug();
420                 break;
421         }
422
423         return TRUE;
424 }
425
426 static guint setup_signalfd(void)
427 {
428         GIOChannel *channel;
429         guint source;
430         sigset_t mask;
431         int fd;
432
433         sigemptyset(&mask);
434         sigaddset(&mask, SIGINT);
435         sigaddset(&mask, SIGTERM);
436         sigaddset(&mask, SIGUSR2);
437
438         if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
439                 perror("Failed to set signal mask");
440                 return 0;
441         }
442
443         fd = signalfd(-1, &mask, 0);
444         if (fd < 0) {
445                 perror("Failed to create signal descriptor");
446                 return 0;
447         }
448
449         channel = g_io_channel_unix_new(fd);
450
451         g_io_channel_set_close_on_unref(channel, TRUE);
452         g_io_channel_set_encoding(channel, NULL, NULL);
453         g_io_channel_set_buffered(channel, FALSE);
454
455         source = g_io_add_watch(channel,
456                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
457                                 signal_handler, NULL);
458
459         g_io_channel_unref(channel);
460
461         return source;
462 }
463
464 static char *option_debug = NULL;
465 static char *option_plugin = NULL;
466 static char *option_noplugin = NULL;
467 static gboolean option_compat = FALSE;
468 static gboolean option_detach = TRUE;
469 static gboolean option_version = FALSE;
470 static gboolean option_experimental = FALSE;
471
472 static void free_options(void)
473 {
474         g_free(option_debug);
475         option_debug = NULL;
476
477         g_free(option_plugin);
478         option_plugin = NULL;
479
480         g_free(option_noplugin);
481         option_noplugin = NULL;
482 }
483
484 static void disconnect_dbus(void)
485 {
486         DBusConnection *conn = btd_get_dbus_connection();
487
488         if (!conn || !dbus_connection_get_is_connected(conn))
489                 return;
490
491         g_dbus_detach_object_manager(conn);
492         set_dbus_connection(NULL);
493
494         dbus_connection_unref(conn);
495 }
496
497 static void disconnected_dbus(DBusConnection *conn, void *data)
498 {
499         info("Disconnected from D-Bus. Exiting.");
500         g_main_loop_quit(event_loop);
501 }
502
503 static int connect_dbus(void)
504 {
505         DBusConnection *conn;
506         DBusError err;
507
508         dbus_error_init(&err);
509
510         conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err);
511         if (!conn) {
512                 if (dbus_error_is_set(&err)) {
513                         g_printerr("D-Bus setup failed: %s\n", err.message);
514                         dbus_error_free(&err);
515                         return -EIO;
516                 }
517                 return -EALREADY;
518         }
519
520         set_dbus_connection(conn);
521
522         g_dbus_set_disconnect_function(conn, disconnected_dbus, NULL, NULL);
523         g_dbus_attach_object_manager(conn);
524
525         return 0;
526 }
527
528 static gboolean watchdog_callback(gpointer user_data)
529 {
530         sd_notify(0, "WATCHDOG=1");
531
532         return TRUE;
533 }
534
535 static gboolean parse_debug(const char *key, const char *value,
536                                 gpointer user_data, GError **error)
537 {
538         if (value)
539                 option_debug = g_strdup(value);
540         else
541                 option_debug = g_strdup("*");
542
543         return TRUE;
544 }
545
546 static GOptionEntry options[] = {
547         { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
548                                 G_OPTION_ARG_CALLBACK, parse_debug,
549                                 "Specify debug options to enable", "DEBUG" },
550         { "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
551                                 "Specify plugins to load", "NAME,..," },
552         { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
553                                 "Specify plugins not to load", "NAME,..." },
554         { "compat", 'C', 0, G_OPTION_ARG_NONE, &option_compat,
555                                 "Provide deprecated command line interfaces" },
556         { "experimental", 'E', 0, G_OPTION_ARG_NONE, &option_experimental,
557                                 "Enable experimental interfaces" },
558         { "nodetach", 'n', G_OPTION_FLAG_REVERSE,
559                                 G_OPTION_ARG_NONE, &option_detach,
560                                 "Run with logging in foreground" },
561         { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
562                                 "Show version information and exit" },
563         { NULL },
564 };
565
566 int main(int argc, char *argv[])
567 {
568         GOptionContext *context;
569         GError *err = NULL;
570         uint16_t sdp_mtu = 0;
571         uint32_t sdp_flags = 0;
572         int gdbus_flags = 0;
573         guint signal, watchdog;
574         const char *watchdog_usec;
575
576         init_defaults();
577
578         context = g_option_context_new(NULL);
579         g_option_context_add_main_entries(context, options, NULL);
580
581         if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
582                 if (err != NULL) {
583                         g_printerr("%s\n", err->message);
584                         g_error_free(err);
585                 } else
586                         g_printerr("An unknown error occurred\n");
587                 exit(1);
588         }
589
590         g_option_context_free(context);
591
592         if (option_version == TRUE) {
593                 printf("%s\n", VERSION);
594                 exit(0);
595         }
596
597         umask(0077);
598
599         event_loop = g_main_loop_new(NULL, FALSE);
600
601         signal = setup_signalfd();
602
603         __btd_log_init(option_debug, option_detach);
604
605         sd_notify(0, "STATUS=Starting up");
606
607         main_conf = load_config(CONFIGDIR "/main.conf");
608
609         parse_config(main_conf);
610
611         if (connect_dbus() < 0) {
612                 error("Unable to get on D-Bus");
613                 exit(1);
614         }
615
616         if (option_experimental)
617                 gdbus_flags = G_DBUS_FLAG_ENABLE_EXPERIMENTAL;
618
619         g_dbus_set_flags(gdbus_flags);
620
621 #ifdef __TIZEN_PATCH__
622         gatt_init();
623 #endif
624
625         if (adapter_init() < 0) {
626                 error("Adapter handling initialization failed");
627                 exit(1);
628         }
629
630         btd_device_init();
631         btd_agent_init();
632         btd_profile_init();
633
634         if (option_compat == TRUE)
635                 sdp_flags |= SDP_SERVER_COMPAT;
636
637         start_sdp_server(sdp_mtu, sdp_flags);
638
639         if (main_opts.did_source > 0)
640                 register_device_id(main_opts.did_source, main_opts.did_vendor,
641                                 main_opts.did_product, main_opts.did_version);
642
643         if (mps != MPS_OFF)
644                 register_mps(mps == MPS_MULTIPLE);
645
646         /* Loading plugins has to be done after D-Bus has been setup since
647          * the plugins might wanna expose some paths on the bus. However the
648          * best order of how to init various subsystems of the Bluetooth
649          * daemon needs to be re-worked. */
650         plugin_init(option_plugin, option_noplugin);
651
652         /* no need to keep parsed option in memory */
653         free_options();
654
655         rfkill_init();
656
657         DBG("Entering main loop");
658
659         sd_notify(0, "STATUS=Running");
660         sd_notify(0, "READY=1");
661
662         watchdog_usec = getenv("WATCHDOG_USEC");
663         if (watchdog_usec) {
664                 unsigned int seconds;
665
666                 seconds = atoi(watchdog_usec) / (1000 * 1000);
667                 info("Watchdog timeout is %d seconds", seconds);
668
669                 watchdog = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
670                                                         seconds / 2,
671                                                         watchdog_callback,
672                                                         NULL, NULL);
673         } else
674                 watchdog = 0;
675
676         g_main_loop_run(event_loop);
677
678         sd_notify(0, "STATUS=Quitting");
679
680         g_source_remove(signal);
681
682         plugin_cleanup();
683
684         btd_profile_cleanup();
685         btd_agent_cleanup();
686         btd_device_cleanup();
687
688         adapter_cleanup();
689
690 #ifdef __TIZEN_PATCH__
691         gatt_cleanup();
692 #endif
693
694         rfkill_exit();
695
696         stop_sdp_server();
697
698         g_main_loop_unref(event_loop);
699
700         if (main_conf)
701                 g_key_file_free(main_conf);
702
703         disconnect_dbus();
704
705         info("Exit");
706
707         if (watchdog > 0)
708                 g_source_remove(watchdog);
709
710         __btd_log_cleanup();
711
712         return 0;
713 }