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