overnet_core/
handle_info.rs

1// Copyright 2020 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 anyhow::{Error, bail};
6use fidl::HandleRef;
7use fidl_fuchsia_overnet_protocol::{ChannelRights, EventPairRights, SocketRights, SocketType};
8
9#[cfg(not(target_os = "fuchsia"))]
10use fidl::EmulatedHandleRef;
11
12#[cfg(target_os = "fuchsia")]
13pub(crate) type HandleKey = zx::Koid;
14
15#[cfg(not(target_os = "fuchsia"))]
16pub(crate) type HandleKey = u64;
17
18/// When sending a datagram on a channel, contains information needed to establish streams
19/// for any handles being sent.
20#[derive(Copy, Clone, Debug)]
21pub(crate) enum HandleType {
22    /// A handle of type channel is being sent.
23    Channel(ChannelRights),
24    Socket(SocketType, SocketRights),
25    EventPair,
26}
27
28#[derive(Copy, Clone, Debug)]
29pub(crate) struct HandleInfo {
30    pub(crate) handle_type: HandleType,
31    pub(crate) this_handle_key: HandleKey,
32    pub(crate) pair_handle_key: HandleKey,
33}
34
35#[cfg(not(target_os = "fuchsia"))]
36pub(crate) fn handle_info(hdl: HandleRef<'_>) -> Result<HandleInfo, Error> {
37    let handle_type = match hdl.object_type() {
38        fidl::ObjectType::CHANNEL => {
39            HandleType::Channel(ChannelRights::READ | ChannelRights::WRITE)
40        }
41        fidl::ObjectType::SOCKET => {
42            HandleType::Socket(SocketType::Stream, SocketRights::READ | SocketRights::WRITE)
43        }
44        fidl::ObjectType::EVENTPAIR => HandleType::EventPair,
45        _ => bail!("Unsupported handle type"),
46    };
47    let (this_handle_key, pair_handle_key) = hdl.koid_pair();
48    Ok(HandleInfo { handle_type, this_handle_key, pair_handle_key })
49}
50
51#[cfg(target_os = "fuchsia")]
52pub(crate) fn handle_info(handle: HandleRef<'_>) -> Result<HandleInfo, Error> {
53    let basic_info = handle.basic_info()?;
54
55    let handle_type = match basic_info.object_type {
56        zx::ObjectType::CHANNEL => {
57            let mut rights = ChannelRights::empty();
58            rights.set(ChannelRights::READ, basic_info.rights.contains(zx::Rights::READ));
59            rights.set(ChannelRights::WRITE, basic_info.rights.contains(zx::Rights::WRITE));
60            HandleType::Channel(rights)
61        }
62        zx::ObjectType::SOCKET => {
63            let socket = handle.cast::<zx::Socket>();
64            let info = socket.info()?;
65            let socket_type = match info.options {
66                zx::SocketOpts::STREAM => SocketType::Stream,
67                zx::SocketOpts::DATAGRAM => SocketType::Datagram,
68                _ => bail!("Unhandled socket options"),
69            };
70            let mut rights = SocketRights::empty();
71            rights.set(SocketRights::READ, basic_info.rights.contains(zx::Rights::READ));
72            rights.set(SocketRights::WRITE, basic_info.rights.contains(zx::Rights::WRITE));
73            HandleType::Socket(socket_type, rights)
74        }
75        zx::ObjectType::EVENTPAIR => HandleType::EventPair,
76        _ => bail!("Handle type not proxyable {:?}", handle.basic_info()?.object_type),
77    };
78
79    Ok(HandleInfo {
80        handle_type,
81        this_handle_key: basic_info.koid,
82        pair_handle_key: basic_info.related_koid,
83    })
84}
85
86pub(crate) trait WithRights {
87    type Rights;
88    fn with_rights(self, rights: Self::Rights) -> Result<Self, Error>
89    where
90        Self: Sized;
91}
92
93#[cfg(target_os = "fuchsia")]
94impl WithRights for fidl::Channel {
95    type Rights = ChannelRights;
96    fn with_rights(self, rights: ChannelRights) -> Result<Self, Error> {
97        use zx::HandleBased;
98        let mut zx_rights = self.basic_info()?.rights;
99        zx_rights.set(zx::Rights::READ, rights.contains(ChannelRights::READ));
100        zx_rights.set(zx::Rights::WRITE, rights.contains(ChannelRights::WRITE));
101        zx_rights.insert(zx::Rights::TRANSFER);
102        Ok(self.replace_handle(zx_rights)?)
103    }
104}
105
106#[cfg(target_os = "fuchsia")]
107impl WithRights for fidl::Socket {
108    type Rights = SocketRights;
109    fn with_rights(self, rights: SocketRights) -> Result<Self, Error> {
110        use zx::HandleBased;
111        let mut zx_rights = self.basic_info()?.rights;
112        zx_rights.set(zx::Rights::READ, rights.contains(SocketRights::READ));
113        zx_rights.set(zx::Rights::WRITE, rights.contains(SocketRights::WRITE));
114        zx_rights.insert(zx::Rights::TRANSFER);
115        Ok(self.replace_handle(zx_rights)?)
116    }
117}
118
119#[cfg(not(target_os = "fuchsia"))]
120impl WithRights for fidl::Channel {
121    type Rights = ChannelRights;
122    fn with_rights(self, rights: ChannelRights) -> Result<Self, Error> {
123        if rights != ChannelRights::READ | ChannelRights::WRITE {
124            bail!("Restricted rights not supported on non-Fuchsia platforms");
125        }
126        Ok(self)
127    }
128}
129
130#[cfg(not(target_os = "fuchsia"))]
131impl WithRights for fidl::Socket {
132    type Rights = SocketRights;
133    fn with_rights(self, rights: SocketRights) -> Result<Self, Error> {
134        if rights != SocketRights::READ | SocketRights::WRITE {
135            bail!("Restricted rights not supported on non-Fuchsia platforms");
136        }
137        Ok(self)
138    }
139}
140
141impl WithRights for fidl::EventPair {
142    type Rights = EventPairRights;
143    fn with_rights(self, rights: EventPairRights) -> Result<Self, Error> {
144        if !rights.is_empty() {
145            bail!("Non-empty rights ({:?}) not supported for event pair", rights);
146        }
147        Ok(self)
148    }
149}