1 use bt_topshim::btif::BluetoothInterface;
2 use bt_topshim::topstack;
3
4 use dbus::channel::MatchingReceiver;
5 use dbus::message::MatchRule;
6
7 use dbus_crossroads::Crossroads;
8
9 use dbus_projection::DisconnectWatcher;
10
11 use dbus_tokio::connection;
12
13 use futures::future;
14
15 use btstack::bluetooth::btif_bluetooth_callbacks;
16 use btstack::bluetooth::Bluetooth;
17 use btstack::bluetooth_gatt::BluetoothGatt;
18 use btstack::Stack;
19
20 use std::error::Error;
21 use std::sync::{Arc, Mutex};
22
23 mod dbus_arg;
24 mod iface_bluetooth;
25 mod iface_bluetooth_gatt;
26
27 const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
28 const OBJECT_BLUETOOTH: &str = "/org/chromium/bluetooth/adapter";
29 const OBJECT_BLUETOOTH_GATT: &str = "/org/chromium/bluetooth/gatt";
30
31 /// Runs the Bluetooth daemon serving D-Bus IPC.
main() -> Result<(), Box<dyn Error>>32 fn main() -> Result<(), Box<dyn Error>> {
33 let (tx, rx) = Stack::create_channel();
34
35 let intf = Arc::new(Mutex::new(BluetoothInterface::new()));
36 let bluetooth = Arc::new(Mutex::new(Bluetooth::new(tx.clone(), intf.clone())));
37 let bluetooth_gatt = Arc::new(Mutex::new(BluetoothGatt::new(intf.clone())));
38
39 topstack::get_runtime().block_on(async {
40 // Connect to D-Bus system bus.
41 let (resource, conn) = connection::new_system_sync()?;
42
43 // The `resource` is a task that should be spawned onto a tokio compatible
44 // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
45 topstack::get_runtime().spawn(async {
46 let err = resource.await;
47 panic!("Lost connection to D-Bus: {}", err);
48 });
49
50 // Request a service name and quit if not able to.
51 conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;
52
53 // Prepare D-Bus interfaces.
54 let mut cr = Crossroads::new();
55 cr.set_async_support(Some((
56 conn.clone(),
57 Box::new(|x| {
58 topstack::get_runtime().spawn(x);
59 }),
60 )));
61
62 intf.lock().unwrap().initialize(Arc::new(btif_bluetooth_callbacks(tx)), vec![]);
63
64 // Run the stack main dispatch loop.
65 topstack::get_runtime().spawn(Stack::dispatch(rx, bluetooth.clone()));
66
67 // Set up the disconnect watcher to monitor client disconnects.
68 let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
69 disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await;
70
71 // Register D-Bus method handlers of IBluetooth.
72 iface_bluetooth::export_bluetooth_dbus_obj(
73 OBJECT_BLUETOOTH,
74 conn.clone(),
75 &mut cr,
76 bluetooth,
77 disconnect_watcher.clone(),
78 );
79 // Register D-Bus method handlers of IBluetoothGatt.
80 iface_bluetooth_gatt::export_bluetooth_gatt_dbus_obj(
81 OBJECT_BLUETOOTH_GATT,
82 conn.clone(),
83 &mut cr,
84 bluetooth_gatt,
85 disconnect_watcher.clone(),
86 );
87
88 conn.start_receive(
89 MatchRule::new_method_call(),
90 Box::new(move |msg, conn| {
91 cr.handle_message(msg, conn).unwrap();
92 true
93 }),
94 );
95
96 // Serve clients forever.
97 future::pending::<()>().await;
98 unreachable!()
99 })
100 }
101