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