runtime_capabilities/fidl/
router.rs1use crate::fidl::{IntoFsandboxCapability, RemotableCapability};
6use crate::{
7 Capability, CapabilityBound, Dictionary, Request, Router, RouterResponse, WeakInstanceToken,
8};
9use fidl_fuchsia_component_sandbox as fsandbox;
10use fidl_fuchsia_io as fio;
11use router_error::{Explain, RouterError};
12use std::sync::Arc;
13use vfs::directory::entry::{self, DirectoryEntry, DirectoryEntryAsync, EntryInfo, GetEntryInfo};
14use vfs::execution_scope::ExecutionScope;
15use zx;
16
17impl Request {
18 pub fn into_fsandbox_request(self, token: WeakInstanceToken) -> fsandbox::RouteRequest {
19 let (token_event_pair, server) = zx::EventPair::create();
20 token.clone().register(token_event_pair.koid().unwrap(), server);
21 let fsandbox::Capability::Dictionary(dictionary_ref) =
22 self.metadata.into_fsandbox_capability(token)
23 else {
24 panic!("invalid type");
25 };
26 fsandbox::RouteRequest {
27 requesting: Some(fsandbox::InstanceToken { token: token_event_pair }),
28 metadata: Some(dictionary_ref),
29 ..Default::default()
30 }
31 }
32}
33
34impl TryFrom<fsandbox::DictionaryRouterRouteResponse> for RouterResponse<Dictionary> {
35 type Error = crate::RemoteError;
36
37 fn try_from(resp: fsandbox::DictionaryRouterRouteResponse) -> Result<Self, Self::Error> {
38 Ok(match resp {
39 fsandbox::DictionaryRouterRouteResponse::Dictionary(dict) => {
40 RouterResponse::<Dictionary>::Capability(dict.try_into()?)
41 }
42 fsandbox::DictionaryRouterRouteResponse::Unavailable(_) => RouterResponse::Unavailable,
43 })
44 }
45}
46
47pub(crate) async fn route_from_fidl<T, R>(
50 router: &Router<T>,
51 payload: fsandbox::RouteRequest,
52 token: WeakInstanceToken,
53) -> Result<R, fsandbox::RouterError>
54where
55 T: CapabilityBound,
56 R: TryFrom<RouterResponse<T>, Error = fsandbox::RouterError>,
57{
58 let resp = match (payload.requesting, payload.metadata) {
59 (Some(token), Some(metadata)) => {
60 let capability =
61 crate::fidl::registry::get(token.token.as_handle_ref().koid().unwrap());
62 let component = match capability {
63 Some(crate::Capability::Instance(c)) => c,
64 Some(_) => return Err(fsandbox::RouterError::InvalidArgs),
65 None => return Err(fsandbox::RouterError::InvalidArgs),
66 };
67 let Capability::Dictionary(metadata) =
68 Capability::try_from(fsandbox::Capability::Dictionary(metadata)).unwrap()
69 else {
70 return Err(fsandbox::RouterError::InvalidArgs);
71 };
72 let request = Request { metadata };
73 router.route(Some(request), false, component).await?
74 }
75 (None, None) => router.route(None, false, token).await?,
76 _ => {
77 return Err(fsandbox::RouterError::InvalidArgs);
78 }
79 };
80 resp.try_into()
81}
82
83impl<T: CapabilityBound + Clone> Router<T>
84where
85 Capability: From<T>,
86{
87 pub(crate) fn into_directory_entry(
88 self,
89 entry_type: fio::DirentType,
90 scope: ExecutionScope,
91 token: WeakInstanceToken,
92 ) -> Arc<dyn DirectoryEntry> {
93 struct RouterEntry<T: CapabilityBound> {
94 router: Router<T>,
95 entry_type: fio::DirentType,
96 scope: ExecutionScope,
97 token: WeakInstanceToken,
98 }
99
100 impl<T: CapabilityBound + Clone> DirectoryEntry for RouterEntry<T>
101 where
102 Capability: From<T>,
103 {
104 fn open_entry(
105 self: Arc<Self>,
106 mut request: entry::OpenRequest<'_>,
107 ) -> Result<(), zx::Status> {
108 request.set_scope(self.scope.clone());
109 request.spawn(self);
110 Ok(())
111 }
112 }
113
114 impl<T: CapabilityBound> GetEntryInfo for RouterEntry<T> {
115 fn entry_info(&self) -> EntryInfo {
116 EntryInfo::new(fio::INO_UNKNOWN, self.entry_type)
117 }
118 }
119
120 impl<T: CapabilityBound + Clone> DirectoryEntryAsync for RouterEntry<T>
121 where
122 Capability: From<T>,
123 {
124 async fn open_entry_async(
125 self: Arc<Self>,
126 open_request: entry::OpenRequest<'_>,
127 ) -> Result<(), zx::Status> {
128 let Some(_guard) = open_request.scope().try_active_guard() else {
131 return Err(zx::Status::PEER_CLOSED);
132 };
133
134 let result = match self.router.route(None, false, self.token.clone()).await {
136 Ok(RouterResponse::<T>::Capability(c)) => Ok(Capability::from(c)),
137 Ok(RouterResponse::<T>::Unavailable) => {
138 return Err(zx::Status::NOT_FOUND);
139 }
140 Ok(RouterResponse::<T>::Debug(_)) => {
141 return Err(zx::Status::INTERNAL);
143 }
144 Err(e) => Err(e),
145 };
146 let error = match result {
147 Ok(capability) => {
148 match capability
149 .try_into_directory_entry(self.scope.clone(), self.token.clone())
150 {
151 Ok(open) => return open.open_entry(open_request),
152 Err(_) => RouterError::NotSupported,
153 }
154 }
155 Err(error) => error, };
157 Err(error.as_zx_status())
158 }
159 }
160
161 Arc::new(RouterEntry { router: self, entry_type, scope, token })
162 }
163}