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