1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
mod bluetooth_manager;
mod bluetooth_manager_dbus;
mod config_util;
mod dbus_arg;
mod state_machine;
use crate::bluetooth_manager::BluetoothManager;
use dbus::channel::MatchingReceiver;
use dbus::message::MatchRule;
use dbus_crossroads::Crossroads;
use dbus_projection::DisconnectWatcher;
use dbus_tokio::connection;
use log::LevelFilter;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
use syslog::{BasicLogger, Facility, Formatter3164};
#[derive(Clone)]
struct ManagerContext {
proxy: state_machine::StateMachineProxy,
floss_enabled: Arc<AtomicBool>,
}
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let formatter = Formatter3164 {
facility: Facility::LOG_USER,
hostname: None,
process: "btmanagerd".into(),
pid: 0,
};
let logger = syslog::unix(formatter).expect("could not connect to syslog");
let _ = log::set_boxed_logger(Box::new(BasicLogger::new(logger)))
.map(|()| log::set_max_level(config_util::get_log_level().unwrap_or(LevelFilter::Info)));
// Initialize config util
config_util::fix_config_file_format();
// Connect to the D-Bus system bus (this is blocking, unfortunately).
let (resource, conn) = connection::new_system_sync()?;
// Determine whether to use upstart or systemd
let args: Vec<String> = std::env::args().collect();
let invoker = if args.len() > 1 {
match &args[1][0..] {
"--systemd" | "-s" => state_machine::Invoker::SystemdInvoker,
_ => state_machine::Invoker::UpstartInvoker,
}
} else {
state_machine::Invoker::UpstartInvoker
};
let context = state_machine::start_new_state_machine_context(invoker);
let proxy = context.get_proxy();
let manager_context = ManagerContext {
proxy: proxy,
floss_enabled: Arc::new(AtomicBool::new(config_util::is_floss_enabled())),
};
// The resource is a task that should be spawned onto a tokio compatible
// reactor ASAP. If the resource ever finishes, you lost connection to D-Bus.
tokio::spawn(async {
let err = resource.await;
panic!("Lost connection to D-Bus: {}", err);
});
// Let's request a name on the bus, so that clients can find us.
conn.request_name("org.chromium.bluetooth.Manager", false, true, false).await?;
// Create a new crossroads instance.
// The instance is configured so that introspection and properties interfaces
// are added by default on object path additions.
let mut cr = Crossroads::new();
// Enable async support for the crossroads instance.
cr.set_async_support(Some((
conn.clone(),
Box::new(|x| {
tokio::spawn(x);
}),
)));
// Object manager is necessary for clients (to inform them when Bluetooth is
// available). Create it at root (/) so subsequent additions generate
// InterfaceAdded and InterfaceRemoved signals.
cr.set_object_manager_support(Some(conn.clone()));
cr.insert("/", &[cr.object_manager()], {});
let bluetooth_manager = Arc::new(Mutex::new(Box::new(BluetoothManager::new(manager_context))));
// Set up the disconnect watcher to monitor client disconnects.
let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await;
// Let's add the "/org/chromium/bluetooth/Manager" path, which implements
// the org.chromium.bluetooth.Manager interface, to the crossroads instance.
bluetooth_manager_dbus::export_bluetooth_manager_dbus_obj(
"/org/chromium/bluetooth/Manager",
conn.clone(),
&mut cr,
bluetooth_manager.clone(),
disconnect_watcher.clone(),
);
// We add the Crossroads instance to the connection so that incoming method calls will be handled.
conn.start_receive(
MatchRule::new_method_call(),
Box::new(move |msg, conn| {
cr.handle_message(msg, conn).unwrap();
true
}),
);
tokio::spawn(async move {
state_machine::mainloop(context, bluetooth_manager).await;
});
std::future::pending::<()>().await;
// Run forever.
unreachable!()
}
|