OSDN Git Service

rusty-gd: implement connection complete for classic acl
authorZach Johnson <zachoverflow@google.com>
Wed, 30 Dec 2020 22:40:07 +0000 (14:40 -0800)
committerZach Johnson <zachoverflow@google.com>
Wed, 20 Jan 2021 00:55:52 +0000 (16:55 -0800)
still not hooked up into the core dispatch yet, coming soon

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost
Change-Id: I32c487719ab55cfb6996a308e4c3998a08c5a078

gd/rust/acl/src/classic.rs

index 43fcdf0..07211bf 100644 (file)
@@ -1,16 +1,19 @@
 //! Classic ACL manager
 
-use bt_hci::{Address, CommandSender};
+use bt_hci::{Address, CommandSender, EventRegistry};
+use bt_packets::hci::EventChild::ConnectionComplete;
 use bt_packets::hci::{
     ClockOffsetValid, CreateConnectionBuilder, CreateConnectionCancelBuilder,
-    CreateConnectionRoleSwitch, PageScanRepetitionMode,
+    CreateConnectionRoleSwitch, ErrorCode, EventCode, PageScanRepetitionMode, Role,
 };
 use gddi::{module, provides, Stoppable};
+use log::warn;
+use std::collections::HashMap;
 use std::sync::Arc;
 use tokio::runtime::Runtime;
 use tokio::select;
-use tokio::sync::mpsc::{channel, Sender};
-use tokio::sync::oneshot;
+use tokio::sync::mpsc::{channel, Receiver, Sender};
+use tokio::sync::{oneshot, Mutex};
 
 module! {
     classic_acl_module,
@@ -23,6 +26,40 @@ module! {
 #[derive(Clone, Stoppable)]
 pub struct AclManager {
     req_tx: Sender<Request>,
+    /// High level events from AclManager
+    pub evt_rx: Arc<Mutex<Receiver<Event>>>,
+}
+
+/// Events generated by AclManager
+#[derive(Debug)]
+pub enum Event {
+    /// Connection was successful - provides the newly created connection
+    ConnectSuccess(Connection),
+    /// Locally initialted connection was not successful - indicates address & reason
+    ConnectFail {
+        /// Address of the failed connection
+        addr: Address,
+        /// Reason of the failed connection
+        reason: ErrorCode,
+    },
+}
+
+/// A classic ACL connection
+#[derive(Debug)]
+pub struct Connection {
+    addr: Address,
+    shared: Arc<Mutex<ConnectionShared>>,
+}
+
+struct ConnectionInternal {
+    addr: Address,
+    #[allow(dead_code)]
+    shared: Arc<Mutex<ConnectionShared>>,
+}
+
+#[derive(Debug)]
+struct ConnectionShared {
+    role: Role,
 }
 
 impl AclManager {
@@ -45,39 +82,97 @@ enum Request {
     CancelConnect { addr: Address, fut: oneshot::Sender<()> },
 }
 
+#[derive(Eq, PartialEq)]
+enum PendingConnect {
+    Outgoing(Address),
+    #[allow(dead_code)]
+    Incoming(Address),
+    None,
+}
+
+impl PendingConnect {
+    fn take(&mut self) -> Self {
+        std::mem::replace(self, PendingConnect::None)
+    }
+}
+
 #[provides]
-async fn provide_acl_manager(mut hci: CommandSender, rt: Arc<Runtime>) -> AclManager {
+async fn provide_acl_manager(
+    mut hci: CommandSender,
+    mut events: EventRegistry,
+    rt: Arc<Runtime>,
+) -> AclManager {
     let (req_tx, mut req_rx) = channel::<Request>(10);
+    let (conn_evt_tx, conn_evt_rx) = channel::<Event>(10);
 
     rt.spawn(async move {
-        let mut pending_connects: Vec<Address> = Vec::new();
-        let mut outgoing_connect: Option<Address> = None;
+        let mut connections: HashMap<u16, ConnectionInternal> = HashMap::new();
+        let mut connect_queue: Vec<Address> = Vec::new();
+        let mut pending = PendingConnect::None;
+
+        let (evt_tx, mut evt_rx) = channel(3);
+        events.register(EventCode::ConnectionComplete, evt_tx).await;
+
         loop {
             select! {
                 Some(req) = req_rx.recv() => {
                     match req {
                         Request::Connect { addr } => {
-                            if outgoing_connect.is_none() {
-                                outgoing_connect = Some(addr);
+                            if connections.values().any(|c| c.addr == addr) {
+                                warn!("already connected: {}", addr);
+                            }
+                            if let PendingConnect::None = pending {
+                                pending = PendingConnect::Outgoing(addr);
                                 hci.send(build_create_connection(addr)).await;
                             } else {
-                                pending_connects.insert(0, addr);
+                                connect_queue.insert(0, addr);
                             }
                         },
                         Request::CancelConnect { addr, fut } => {
-                            pending_connects.retain(|p| *p != addr);
-                            if outgoing_connect == Some(addr) {
+                            connect_queue.retain(|p| *p != addr);
+                            if pending == PendingConnect::Outgoing(addr) {
                                 hci.send(CreateConnectionCancelBuilder { bd_addr: addr }).await;
                             }
                             fut.send(()).unwrap();
                         }
                     }
                 }
+                Some(evt) = evt_rx.recv() => {
+                    match evt.specialize() {
+                        ConnectionComplete(evt) => {
+                            let addr = evt.get_bd_addr();
+                            let status = evt.get_status();
+                            let handle = evt.get_connection_handle();
+                            let role = match pending.take() {
+                                PendingConnect::Outgoing(a) if a == addr => Role::Central,
+                                PendingConnect::Incoming(a) if a == addr => Role::Peripheral,
+                                _ => panic!("No prior connection request for {}", addr),
+                            };
+
+                            match status {
+                                ErrorCode::Success => {
+                                    let shared = Arc::new(Mutex::new(ConnectionShared { role }));
+                                    assert!(connections.insert(
+                                        handle,
+                                        ConnectionInternal { addr, shared: shared.clone() }
+                                    ).is_none());
+
+                                    conn_evt_tx.send(Event::ConnectSuccess(Connection {
+                                        addr,
+                                        shared
+                                    })).await.unwrap();
+                                },
+                                _ => conn_evt_tx.send(Event::ConnectFail { addr, reason: status }).await.unwrap(),
+                            }
+                        },
+                        _ => unimplemented!(),
+                    }
+                }
             }
         }
     });
 
-    AclManager { req_tx }
+    AclManager { req_tx, evt_rx: Arc::new(Mutex::new(conn_evt_rx)) }
 }
 
 fn build_create_connection(bd_addr: Address) -> CreateConnectionBuilder {