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