1// Copyright 2019 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.
45//! Connection to a directory that can not be modified by the client, no matter what permissions
6//! the client has on the FIDL connection.
78use crate::directory::connection::{BaseConnection, ConnectionState};
9use crate::directory::entry_container::Directory;
10use crate::execution_scope::ExecutionScope;
11use crate::node::OpenNode;
12use crate::object_request::ConnectionCreator;
13use crate::request_handler::{RequestHandler, RequestListener};
14use crate::{ObjectRequestRef, ProtocolsExt};
1516use fidl_fuchsia_io as fio;
17use fio::DirectoryRequest;
18use std::ops::ControlFlow;
19use std::pin::Pin;
20use std::sync::Arc;
21use zx_status::Status;
2223pub struct ImmutableConnection<DirectoryType: Directory> {
24 base: BaseConnection<DirectoryType>,
25}
2627impl<DirectoryType: Directory> ImmutableConnection<DirectoryType> {
28/// Creates a new connection to serve the directory. The directory will be served from a new
29 /// async `Task`, not from the current `Task`. Errors in constructing the connection are not
30 /// guaranteed to be returned, they may be sent directly to the client end of the connection.
31 /// This method should be called from within an `ObjectRequest` handler to ensure that errors
32 /// are sent to the client end of the connection.
33pub async fn create(
34 scope: ExecutionScope,
35 directory: Arc<DirectoryType>,
36 protocols: impl ProtocolsExt,
37 object_request: ObjectRequestRef<'_>,
38 ) -> Result<(), Status> {
39Self::create_transform_stream(
40 scope,
41 directory,
42 protocols,
43 object_request,
44 std::convert::identity,
45 )
46 .await
47}
4849/// TODO(https://fxbug.dev/326626515): this is an experimental method to run a FIDL
50 /// directory connection until stalled, with the purpose to cleanly stop a component.
51 /// We'll expect to revisit how this works to generalize to all connections later.
52 /// Try not to use this function for other purposes.
53pub async fn create_transform_stream<Transform, RS>(
54 scope: ExecutionScope,
55 directory: Arc<DirectoryType>,
56 protocols: impl ProtocolsExt,
57 object_request: ObjectRequestRef<'_>,
58 transform: Transform,
59 ) -> Result<(), Status>
60where
61Transform: FnOnce(fio::DirectoryRequestStream) -> RS,
62 RS: futures::stream::Stream<Item = Result<DirectoryRequest, fidl::Error>> + Send + 'static,
63 {
64// Ensure we close the directory if we fail to create the connection.
65let directory = OpenNode::new(directory);
6667let connection = ImmutableConnection {
68 base: BaseConnection::new(scope.clone(), directory, protocols.to_directory_options()?),
69 };
7071// If we fail to send the task to the executor, it is probably shut down or is in the
72 // process of shutting down (this is the only error state currently). So there is nothing
73 // for us to do - the connection will be closed automatically when the connection object is
74 // dropped.
75if let Ok(requests) = object_request.take().into_request_stream(&connection.base).await {
76 scope.spawn(RequestListener::new(transform(requests), connection));
77 }
78Ok(())
79 }
80}
8182impl<DirectoryType: Directory> RequestHandler for ImmutableConnection<DirectoryType> {
83type Request = Result<DirectoryRequest, fidl::Error>;
8485async fn handle_request(self: Pin<&mut Self>, request: Self::Request) -> ControlFlow<()> {
86let this = self.get_mut();
87let _guard = this.base.scope.active_guard();
88match request {
89Ok(request) => match this.base.handle_request(request).await {
90Ok(ConnectionState::Alive) => ControlFlow::Continue(()),
91Ok(ConnectionState::Closed) | Err(_) => ControlFlow::Break(()),
92 },
93Err(_) => ControlFlow::Break(()),
94 }
95 }
96}
9798impl<DirectoryType: Directory> ConnectionCreator<DirectoryType>
99for ImmutableConnection<DirectoryType>
100{
101async fn create<'a>(
102 scope: ExecutionScope,
103 node: Arc<DirectoryType>,
104 protocols: impl ProtocolsExt,
105 object_request: ObjectRequestRef<'a>,
106 ) -> Result<(), Status> {
107Self::create(scope, node, protocols, object_request).await
108}
109}