Loading system/gd/rust/linux/client/src/callbacks.rs +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, Loading Loading @@ -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 { Loading Loading @@ -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>>, } Loading @@ -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 { Loading Loading @@ -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); })); } Loading @@ -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( Loading @@ -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); } Loading system/gd/rust/linux/client/src/command_handler.rs +112 −50 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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> { Loading Loading @@ -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, Loading Loading @@ -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!( Loading @@ -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, Loading @@ -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()) { Loading @@ -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 { Loading system/gd/rust/linux/client/src/main.rs +5 −1 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 { Loading Loading @@ -162,6 +165,7 @@ impl ClientContext { socket_manager_callback_id: None, is_restricted, gatt_client_context: GattClientContext::new(), socket_test_schedule: None, } } Loading Loading
system/gd/rust/linux/client/src/callbacks.rs +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, Loading Loading @@ -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 { Loading Loading @@ -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>>, } Loading @@ -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 { Loading Loading @@ -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); })); } Loading @@ -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( Loading @@ -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); } Loading
system/gd/rust/linux/client/src/command_handler.rs +112 −50 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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> { Loading Loading @@ -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, Loading Loading @@ -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!( Loading @@ -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, Loading @@ -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()) { Loading @@ -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 { Loading
system/gd/rust/linux/client/src/main.rs +5 −1 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 { Loading Loading @@ -162,6 +165,7 @@ impl ClientContext { socket_manager_callback_id: None, is_restricted, gatt_client_context: GattClientContext::new(), socket_test_schedule: None, } } Loading