Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03a96c1a authored by Yun-hao Chung's avatar Yun-hao Chung Committed by Automerger Merge Worker
Browse files

Merge "Floss: Implement commands for socket test schedule" am: ae92107d

parents c3b5307d ae92107d
Loading
Loading
Loading
Loading
+55 −13
Original line number Diff line number Diff line
use crate::command_handler::SocketSchedule;
use crate::dbus_iface::{
    export_admin_policy_callback_dbus_intf, export_advertising_set_callback_dbus_intf,
    export_bluetooth_callback_dbus_intf, export_bluetooth_connection_callback_dbus_intf,
@@ -29,7 +30,11 @@ use dbus::nonblock::SyncConnection;
use dbus_crossroads::Crossroads;
use dbus_projection::DisconnectWatcher;
use manager_service::iface_bluetooth_manager::IBluetoothManagerCallback;
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
use std::time::Duration;

const SOCKET_TEST_WRITE: &[u8] = b"01234567890123456789";

/// Callback context for manager interface callbacks.
pub(crate) struct BtManagerCallback {
@@ -962,7 +967,6 @@ impl RPCProxy for BtGattServerCallback {
pub(crate) struct BtSocketManagerCallback {
    objpath: String,
    context: Arc<Mutex<ClientContext>>,

    dbus_connection: Arc<SyncConnection>,
    dbus_crossroads: Arc<Mutex<Crossroads>>,
}
@@ -976,6 +980,44 @@ impl BtSocketManagerCallback {
    ) -> Self {
        Self { objpath, context, dbus_connection, dbus_crossroads }
    }

    fn start_socket_schedule(&mut self, socket: BluetoothSocket) {
        let SocketSchedule { num_frame, send_interval, disconnect_delay } =
            match self.context.lock().unwrap().socket_test_schedule {
                Some(s) => s,
                None => return,
            };

        let mut fd = match socket.fd {
            Some(fd) => fd,
            None => {
                print_error!("incoming connection fd is None. Unable to send data");
                return;
            }
        };

        tokio::spawn(async move {
            for i in 0..num_frame {
                fd.write_all(SOCKET_TEST_WRITE);
                print_info!("data sent: {}", i + 1);
                tokio::time::sleep(send_interval).await;
            }

            // dump any incoming data
            let interval = 100;
            for _d in (0..=disconnect_delay.as_millis()).step_by(interval) {
                let mut buf = [0; 128];
                let sz = fd.read(&mut buf).unwrap();
                let data = buf[..sz].to_vec();
                if sz > 0 {
                    print_info!("received {} bytes: {:?}", sz, data);
                }
                tokio::time::sleep(Duration::from_millis(interval as u64)).await;
            }

            //|fd| is dropped automatically when the scope ends.
        });
    }
}

impl IBluetoothSocketManagerCallbacks for BtSocketManagerCallback {
@@ -1005,18 +1047,16 @@ impl IBluetoothSocketManagerCallbacks for BtSocketManagerCallback {
        let callback_id = self.context.lock().unwrap().socket_manager_callback_id.clone().unwrap();

        self.context.lock().unwrap().run_callback(Box::new(move |context| {
            let status = context
                .lock()
                .unwrap()
                .socket_manager_dbus
                .as_mut()
                .unwrap()
                .close(callback_id, socket.id);
            let status = context.lock().unwrap().socket_manager_dbus.as_mut().unwrap().accept(
                callback_id,
                socket.id,
                None,
            );
            if status != BtStatus::Success {
                print_error!("Failed to close socket {}, status = {:?}", socket.id, status);
                print_error!("Failed to accept socket {}, status = {:?}", socket.id, status);
                return;
            }
            print_info!("Requested for closing socket {}", socket.id);
            print_info!("Requested for accepting socket {}", socket.id);
        }));
    }

@@ -1026,10 +1066,11 @@ impl IBluetoothSocketManagerCallbacks for BtSocketManagerCallback {

    fn on_handle_incoming_connection(
        &mut self,
        _listener_id: SocketId,
        _connection: BluetoothSocket,
        listener_id: SocketId,
        connection: BluetoothSocket,
    ) {
        todo!();
        print_info!("Socket {} connected", listener_id);
        self.start_socket_schedule(connection);
    }

    fn on_outgoing_connection_result(
@@ -1040,6 +1081,7 @@ impl IBluetoothSocketManagerCallbacks for BtSocketManagerCallback {
    ) {
        if let Some(s) = socket {
            print_info!("Connection success on {}: {:?} for {}", connecting_id, result, s);
            self.start_socket_schedule(s);
        } else {
            print_info!("Connection failed on {}: {:?}", connecting_id, result);
        }
+112 −50
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::slice::SliceIndex;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::bt_adv::AdvSet;
use crate::bt_gatt::AuthReq;
@@ -65,6 +66,21 @@ pub(crate) struct CommandHandler {
    command_options: HashMap<String, CommandOption>,
}

/// Define what to do when a socket connects. Mainly for qualification purposes.
/// Specifically, after a socket is connected/accepted, we will do
/// (1) send a chunk of data every |send_interval| time until |num_frame| chunks has been sent.
/// (2) wait another |disconnect_delay| time. any incoming data will be dumpted during this time.
/// (3) disconnect the socket.
#[derive(Copy, Clone)]
pub struct SocketSchedule {
    /// Number of times to send data
    pub num_frame: u32,
    /// Time interval between each sending
    pub send_interval: Duration,
    /// Extra time after the last sending. Any incoming data will be printed during this time.
    pub disconnect_delay: Duration,
}

struct DisplayList<T>(Vec<T>);

impl<T: Display> Display for DisplayList<T> {
@@ -208,8 +224,10 @@ fn build_commands() -> HashMap<String, CommandOption> {
        String::from("socket"),
        CommandOption {
            rules: vec![
                String::from("socket test"),
                String::from("socket connect <addr> <l2cap|rfcomm> <psm|uuid>"),
                String::from("socket listen <auth-required>"),
                String::from("socket connect <address> <l2cap|rfcomm> <psm|uuid> <auth-required>"),
                String::from("socket disconnect <socket_id>"),
                String::from("socket set-on-connect-schedule <send|resend|dump>"),
            ],
            description: String::from("Socket manager utilities."),
            function_pointer: CommandHandler::cmd_socket,
@@ -1252,13 +1270,44 @@ impl CommandHandler {
        let command = get_arg(args, 0)?;

        match &command[..] {
            "test" => {
                let SocketResult { status, id } = self
                    .lock_context()
                    .socket_manager_dbus
                    .as_mut()
                    .unwrap()
                    .listen_using_l2cap_channel(callback_id);
            "set-on-connect-schedule" => {
                let schedule = match &get_arg(args, 1)?[..] {
                    "send" => SocketSchedule {
                        num_frame: 1,
                        send_interval: Duration::from_millis(0),
                        disconnect_delay: Duration::from_secs(30),
                    },
                    "resend" => SocketSchedule {
                        num_frame: 3,
                        send_interval: Duration::from_millis(100),
                        disconnect_delay: Duration::from_secs(30),
                    },
                    "dump" => SocketSchedule {
                        num_frame: 0,
                        send_interval: Duration::from_millis(0),
                        disconnect_delay: Duration::from_secs(30),
                    },
                    _ => {
                        return Err("Failed to parse schedule".into());
                    }
                };

                self.context.lock().unwrap().socket_test_schedule = Some(schedule);
            }
            "listen" => {
                let auth_required = String::from(get_arg(args, 1)?)
                    .parse::<bool>()
                    .or(Err("Failed to parse auth-required"))?;

                let SocketResult { status, id } = {
                    let mut context_proxy = self.context.lock().unwrap();
                    let proxy = context_proxy.socket_manager_dbus.as_mut().unwrap();
                    if auth_required {
                        proxy.listen_using_l2cap_channel(callback_id)
                    } else {
                        proxy.listen_using_insecure_l2cap_channel(callback_id)
                    }
                };

                if status != BtStatus::Success {
                    return Err(format!(
@@ -1277,7 +1326,15 @@ impl CommandHandler {
                    name: String::from("Socket Connect Device"),
                };

                let SocketResult { status, id } = match &sock_type[0..] {
                let auth_required = String::from(get_arg(args, 4)?)
                    .parse::<bool>()
                    .or(Err("Failed to parse auth-required"))?;

                let SocketResult { status, id } = {
                    let mut context_proxy = self.context.lock().unwrap();
                    let proxy = context_proxy.socket_manager_dbus.as_mut().unwrap();

                    match &sock_type[0..] {
                        "l2cap" => {
                            let psm = match psm_or_uuid.clone().parse::<i32>() {
                                Ok(v) => v,
@@ -1289,11 +1346,11 @@ impl CommandHandler {
                                }
                            };

                        self.lock_context()
                            .socket_manager_dbus
                            .as_mut()
                            .unwrap()
                            .create_insecure_l2cap_channel(callback_id, device, psm)
                            if auth_required {
                                proxy.create_l2cap_channel(callback_id, device, psm)
                            } else {
                                proxy.create_insecure_l2cap_channel(callback_id, device, psm)
                            }
                        }
                        "rfcomm" => {
                            let uuid = match UuidHelper::parse_string(psm_or_uuid.clone()) {
@@ -1305,22 +1362,27 @@ impl CommandHandler {
                                }
                            };

                        self.lock_context()
                            .socket_manager_dbus
                            .as_mut()
                            .unwrap()
                            .create_insecure_rfcomm_socket_to_service_record(
                            if auth_required {
                                proxy.create_rfcomm_socket_to_service_record(
                                    callback_id,
                                    device,
                                    uuid,
                                )
                            } else {
                                proxy.create_insecure_rfcomm_socket_to_service_record(
                                    callback_id,
                                    device,
                                    uuid,
                                )
                            }
                        }
                        _ => {
                            return Err(CommandError::Failed(format!(
                                "Unknown socket type: {}",
                                sock_type
                            )));
                        }
                    }
                };

                if status != BtStatus::Success {
+5 −1
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ use crate::callbacks::{
    AdminCallback, AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback,
    BtSocketManagerCallback, ScannerCallback, SuspendCallback,
};
use crate::command_handler::CommandHandler;
use crate::command_handler::{CommandHandler, SocketSchedule};
use crate::dbus_iface::{
    BluetoothAdminDBus, BluetoothDBus, BluetoothGattDBus, BluetoothManagerDBus, BluetoothQADBus,
    BluetoothSocketManagerDBus, SuspendDBus,
@@ -121,6 +121,9 @@ pub(crate) struct ClientContext {

    /// Data of GATT client preference.
    gatt_client_context: GattClientContext,

    /// The schedule when a socket is connected.
    socket_test_schedule: Option<SocketSchedule>,
}

impl ClientContext {
@@ -162,6 +165,7 @@ impl ClientContext {
            socket_manager_callback_id: None,
            is_restricted,
            gatt_client_context: GattClientContext::new(),
            socket_test_schedule: None,
        }
    }