aboutsummaryrefslogtreecommitdiff
path: root/gd/rust/linux/service/src/main.rs
blob: 755c611072c9a0ab3fea1bab75bb0a19f6f6e6be (plain)
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
use bt_topshim::btif::BluetoothInterface;
use bt_topshim::topstack;

use dbus::channel::MatchingReceiver;
use dbus::message::MatchRule;

use dbus_crossroads::Crossroads;

use dbus_projection::DisconnectWatcher;

use dbus_tokio::connection;

use futures::future;

use btstack::bluetooth::btif_bluetooth_callbacks;
use btstack::bluetooth::Bluetooth;
use btstack::bluetooth_gatt::BluetoothGatt;
use btstack::Stack;

use std::error::Error;
use std::sync::{Arc, Mutex};

mod dbus_arg;
mod iface_bluetooth;
mod iface_bluetooth_gatt;

const DBUS_SERVICE_NAME: &str = "org.chromium.bluetooth";
const OBJECT_BLUETOOTH: &str = "/org/chromium/bluetooth/adapter";
const OBJECT_BLUETOOTH_GATT: &str = "/org/chromium/bluetooth/gatt";

/// Runs the Bluetooth daemon serving D-Bus IPC.
fn main() -> Result<(), Box<dyn Error>> {
    let (tx, rx) = Stack::create_channel();

    let intf = Arc::new(Mutex::new(BluetoothInterface::new()));
    let bluetooth = Arc::new(Mutex::new(Bluetooth::new(tx.clone(), intf.clone())));
    let bluetooth_gatt = Arc::new(Mutex::new(BluetoothGatt::new(intf.clone())));

    topstack::get_runtime().block_on(async {
        // Connect to D-Bus system bus.
        let (resource, conn) = connection::new_system_sync()?;

        // The `resource` is a task that should be spawned onto a tokio compatible
        // reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
        topstack::get_runtime().spawn(async {
            let err = resource.await;
            panic!("Lost connection to D-Bus: {}", err);
        });

        // Request a service name and quit if not able to.
        conn.request_name(DBUS_SERVICE_NAME, false, true, false).await?;

        // Prepare D-Bus interfaces.
        let mut cr = Crossroads::new();
        cr.set_async_support(Some((
            conn.clone(),
            Box::new(|x| {
                topstack::get_runtime().spawn(x);
            }),
        )));

        intf.lock().unwrap().initialize(Arc::new(btif_bluetooth_callbacks(tx)), vec![]);

        // Run the stack main dispatch loop.
        topstack::get_runtime().spawn(Stack::dispatch(rx, bluetooth.clone()));

        // 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;

        // Register D-Bus method handlers of IBluetooth.
        iface_bluetooth::export_bluetooth_dbus_obj(
            OBJECT_BLUETOOTH,
            conn.clone(),
            &mut cr,
            bluetooth,
            disconnect_watcher.clone(),
        );
        // Register D-Bus method handlers of IBluetoothGatt.
        iface_bluetooth_gatt::export_bluetooth_gatt_dbus_obj(
            OBJECT_BLUETOOTH_GATT,
            conn.clone(),
            &mut cr,
            bluetooth_gatt,
            disconnect_watcher.clone(),
        );

        conn.start_receive(
            MatchRule::new_method_call(),
            Box::new(move |msg, conn| {
                cr.handle_message(msg, conn).unwrap();
                true
            }),
        );

        // Serve clients forever.
        future::pending::<()>().await;
        unreachable!()
    })
}