Skip to main content

runtime_capabilities/
connector.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{CapabilityBound, Receiver};
6use futures::channel::mpsc;
7use std::fmt::Debug;
8use std::sync::Arc;
9
10/// Types that implement [`Connectable`] let the holder send channels
11/// to them.
12pub trait Connectable: Send + Sync + Debug {
13    fn send(&self, channel: fidl::Channel) -> Result<(), ()>;
14}
15
16impl Connectable for mpsc::UnboundedSender<fidl::Channel> {
17    fn send(&self, channel: fidl::Channel) -> Result<(), ()> {
18        self.unbounded_send(channel).map_err(|_| ())
19    }
20}
21
22/// A capability that transfers another capability to a [Receiver].
23#[derive(Debug)]
24pub struct Connector {
25    inner: Box<dyn Connectable>,
26}
27
28impl CapabilityBound for Connector {
29    fn debug_typename() -> &'static str {
30        "Connector"
31    }
32
33    #[cfg(target_os = "fuchsia")]
34    fn try_into_directory_entry(
35        self: Arc<Self>,
36        _scope: vfs::execution_scope::ExecutionScope,
37        _token: Arc<crate::WeakInstanceToken>,
38    ) -> Result<Arc<dyn vfs::directory::entry::DirectoryEntry>, crate::ConversionError> {
39        Ok(vfs::service::endpoint(move |_scope, server_end| {
40            let _ = self.send(server_end.into_zx_channel().into());
41        }))
42    }
43}
44
45impl Connector {
46    pub fn new() -> (Receiver, Arc<Self>) {
47        let (sender, receiver) = mpsc::unbounded();
48        let receiver = Receiver::new(receiver);
49        let this = Self::new_sendable(sender);
50        (receiver, this)
51    }
52
53    pub fn new_sendable(connector: impl Connectable + 'static) -> Arc<Self> {
54        Arc::new(Self { inner: Box::new(connector) })
55    }
56
57    pub fn send(&self, channel: fidl::Channel) -> Result<(), ()> {
58        self.inner.send(channel)
59    }
60}
61
62impl Connectable for Connector {
63    fn send(&self, channel: fidl::Channel) -> Result<(), ()> {
64        self.send(channel)
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use crate::Capability;
72    use fidl::handle::{Channel, Rights};
73    use fidl_fuchsia_component_sandbox as fsandbox;
74
75    // NOTE: sending-and-receiving tests are written in `receiver.rs`.
76
77    /// Tests that a Connector can be cloned by cloning its FIDL token.
78    /// and capabilities sent to the original and clone arrive at the same Receiver.
79    #[fuchsia::test]
80    async fn fidl_clone() {
81        let (receiver, sender) = Connector::new();
82
83        // Send a channel through the Connector.
84        let (ch1, _ch2) = Channel::create();
85        sender.send(ch1).unwrap();
86
87        // Convert the Sender to a FIDL token.
88        let connector: fsandbox::Connector = sender.to_fsandbox();
89
90        // Clone the Sender by cloning the token.
91        let token_clone = fsandbox::Connector {
92            token: connector.token.duplicate_handle(Rights::SAME_RIGHTS).unwrap(),
93        };
94        let connector_clone =
95            match Capability::try_from(fsandbox::Capability::Connector(token_clone)).unwrap() {
96                Capability::Connector(connector) => connector,
97                capability @ _ => panic!("wrong type {capability:?}"),
98            };
99
100        // Send a channel through the cloned Sender.
101        let (ch1, _ch2) = Channel::create();
102        connector_clone.send(ch1).unwrap();
103
104        // The Receiver should receive two channels, one from each connector.
105        for _ in 0..2 {
106            let _ch = receiver.receive().await.unwrap();
107        }
108    }
109}