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