fidl/
endpoints.rs

1// Copyright 2018 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
5//! Wrapper types for the endpoints of a connection.
6
7use crate::epitaph::ChannelEpitaphExt;
8use crate::{
9    AsHandleRef, AsyncChannel, Channel, Error, HandleBased, HandleRef, NullableHandle,
10    OnSignalsRef, ServeInner,
11};
12use futures::{Stream, TryStream};
13use std::marker::PhantomData;
14use std::sync::Arc;
15
16/// A marker for a particular FIDL protocol.
17///
18/// Implementations of this trait can be used to manufacture instances of a FIDL
19/// protocol and get metadata about a particular protocol.
20pub trait ProtocolMarker: Sized + Send + Sync + 'static {
21    /// The type of the structure against which FIDL requests are made.
22    /// Queries made against the proxy are sent to the paired `ServerEnd`.
23    type Proxy: Proxy<Protocol = Self>;
24
25    /// The type of the structure against which thread-blocking FIDL requests are made.
26    /// Queries made against the proxy are sent to the paired `ServerEnd`.
27    #[cfg(target_os = "fuchsia")]
28    type SynchronousProxy: SynchronousProxy<Protocol = Self>;
29
30    /// The type of the stream of requests coming into a server.
31    type RequestStream: RequestStream<Protocol = Self>;
32
33    /// The name of the protocol suitable for debug purposes.
34    ///
35    /// For discoverable protocols, this should be identical to
36    /// `<Self as DiscoverableProtocolMarker>::PROTOCOL_NAME`.
37    const DEBUG_NAME: &'static str;
38}
39
40/// A marker for a particular FIDL protocol that is also discoverable.
41///
42/// Discoverable protocols may be referred to by a string name, and can be
43/// conveniently exported in a service directory via an entry of that name.
44///
45/// If you get an error about this trait not being implemented, you probably
46/// need to add the `@discoverable` attribute to the FIDL protocol, like this:
47///
48/// ```fidl
49/// @discoverable
50/// protocol MyProtocol { ... };
51/// ```
52pub trait DiscoverableProtocolMarker: ProtocolMarker {
53    /// The name of the protocol (to be used for service lookup and discovery).
54    const PROTOCOL_NAME: &'static str = <Self as ProtocolMarker>::DEBUG_NAME;
55}
56
57/// A type which allows querying a remote FIDL server over a channel.
58pub trait Proxy: Sized + Send + Sync {
59    /// The protocol which this `Proxy` controls.
60    type Protocol: ProtocolMarker<Proxy = Self>;
61
62    /// Create a proxy over the given channel.
63    fn from_channel(inner: AsyncChannel) -> Self;
64
65    /// Attempt to convert the proxy back into a channel.
66    ///
67    /// This will only succeed if there are no active clones of this proxy
68    /// and no currently-alive `EventStream` or response futures that came from
69    /// this proxy.
70    fn into_channel(self) -> Result<AsyncChannel, Self>;
71
72    /// Attempt to convert the proxy back into a client end.
73    ///
74    /// This will only succeed if there are no active clones of this proxy
75    /// and no currently-alive `EventStream` or response futures that came from
76    /// this proxy.
77    fn into_client_end(self) -> Result<ClientEnd<Self::Protocol>, Self> {
78        match self.into_channel() {
79            Ok(channel) => Ok(ClientEnd::new(channel.into_zx_channel())),
80            Err(proxy) => Err(proxy),
81        }
82    }
83
84    /// Get a reference to the proxy's underlying channel.
85    ///
86    /// This should only be used for non-effectful operations. Reading or
87    /// writing to the channel is unsafe because the proxy assumes it has
88    /// exclusive control over these operations.
89    fn as_channel(&self) -> &AsyncChannel;
90
91    /// Returns true if the proxy has received the `PEER_CLOSED` signal.
92    fn is_closed(&self) -> bool {
93        self.as_channel().is_closed()
94    }
95
96    /// Returns a future that completes when the proxy receives the
97    /// `PEER_CLOSED` signal.
98    fn on_closed(&self) -> OnSignalsRef<'_> {
99        self.as_channel().on_closed()
100    }
101}
102
103/// This gives native Zircon proxies a domain method like FDomain proxies have.
104/// This makes it easier in some cases to build the same code for both FDomain
105/// and regular FIDL.
106pub trait ProxyHasDomain {
107    /// Get a "client" for this proxy. This is just an object which has methods
108    /// for a few common handle creation operations.
109    fn domain(&self) -> ZirconClient {
110        ZirconClient
111    }
112}
113
114impl<T: Proxy> ProxyHasDomain for T {}
115
116/// The fake "client" produced by `ProxyHasDomain`. Analogous to an FDomain client.
117pub struct ZirconClient;
118
119impl ZirconClient {
120    /// Equivalent to [`EventPair::create`]
121    pub fn create_event_pair(&self) -> (crate::EventPair, crate::EventPair) {
122        crate::EventPair::create()
123    }
124
125    /// Equivalent to [`Event::create`]
126    pub fn create_event(&self) -> crate::Event {
127        crate::Event::create()
128    }
129
130    /// Equivalent to [`Socket::create_stream`]
131    pub fn create_stream_socket(&self) -> (crate::Socket, crate::Socket) {
132        crate::Socket::create_stream()
133    }
134
135    /// Equivalent to [`Socket::create_datagram`]
136    pub fn create_datagram_socket(&self) -> (crate::Socket, crate::Socket) {
137        crate::Socket::create_datagram()
138    }
139
140    /// Equivalent to [`Channel::create`]
141    pub fn create_channel(&self) -> (Channel, Channel) {
142        Channel::create()
143    }
144
145    /// Equivalent to the module level [`create_endpoints`]
146    pub fn create_endpoints<T: ProtocolMarker>(&self) -> (ClientEnd<T>, ServerEnd<T>) {
147        create_endpoints::<T>()
148    }
149
150    /// Equivalent to the module level [`create_proxy`]
151    pub fn create_proxy<T: ProtocolMarker>(&self) -> (T::Proxy, ServerEnd<T>) {
152        create_proxy::<T>()
153    }
154
155    /// Equivalent to the module level [`create_proxy_and_stream`]
156    pub fn create_proxy_and_stream<T: ProtocolMarker>(&self) -> (T::Proxy, T::RequestStream) {
157        create_proxy_and_stream::<T>()
158    }
159}
160
161/// A type which allows querying a remote FIDL server over a channel, blocking the calling thread.
162#[cfg(target_os = "fuchsia")]
163pub trait SynchronousProxy: Sized + Send + Sync {
164    /// The async proxy for the same protocol.
165    type Proxy: Proxy<Protocol = Self::Protocol>;
166
167    /// The protocol which this `Proxy` controls.
168    type Protocol: ProtocolMarker<Proxy = Self::Proxy>;
169
170    /// Create a proxy over the given channel.
171    fn from_channel(inner: Channel) -> Self;
172
173    /// Convert the proxy back into a channel.
174    fn into_channel(self) -> Channel;
175
176    /// Get a reference to the proxy's underlying channel.
177    ///
178    /// This should only be used for non-effectful operations. Reading or
179    /// writing to the channel is unsafe because the proxy assumes it has
180    /// exclusive control over these operations.
181    fn as_channel(&self) -> &Channel;
182
183    /// Returns true if the proxy has received the `PEER_CLOSED` signal.
184    ///
185    /// # Errors
186    ///
187    /// See https://fuchsia.dev/reference/syscalls/object_wait_one?hl=en#errors for a full list of
188    /// errors. Note that `Status::TIMED_OUT` errors are converted to `Ok(false)` and all other
189    /// errors are propagated.
190    fn is_closed(&self) -> Result<bool, zx::Status> {
191        use zx::Peered;
192        self.as_channel().is_closed()
193    }
194}
195
196/// A stream of requests coming into a FIDL server over a channel.
197pub trait RequestStream: Sized + Send + Stream + TryStream<Error = crate::Error> + Unpin {
198    /// The protocol which this `RequestStream` serves.
199    type Protocol: ProtocolMarker<RequestStream = Self>;
200
201    /// The control handle for this `RequestStream`.
202    type ControlHandle: ControlHandle;
203
204    /// Returns a copy of the `ControlHandle` for the given stream.
205    /// This handle can be used to send events or shut down the request stream.
206    fn control_handle(&self) -> Self::ControlHandle;
207
208    /// Create a request stream from the given channel.
209    fn from_channel(inner: AsyncChannel) -> Self;
210
211    /// Convert this channel into its underlying components.
212    fn into_inner(self) -> (Arc<ServeInner>, bool);
213
214    /// Create this channel from its underlying components.
215    fn from_inner(inner: Arc<ServeInner>, is_terminated: bool) -> Self;
216
217    /// Convert this FIDL request stream into a request stream of another FIDL protocol.
218    fn cast_stream<T: RequestStream>(self) -> T {
219        let inner = self.into_inner();
220        T::from_inner(inner.0, inner.1)
221    }
222}
223
224/// The Request type associated with a Marker.
225pub type Request<Marker> = <<Marker as ProtocolMarker>::RequestStream as futures::TryStream>::Ok;
226
227/// A type associated with a `RequestStream` that can be used to send FIDL
228/// events or to shut down the request stream.
229pub trait ControlHandle {
230    /// Set the server to shutdown. The underlying channel is only closed the
231    /// next time the stream is polled.
232    // TODO(https://fxbug.dev/42161447): Fix behavior or above docs.
233    fn shutdown(&self);
234
235    /// Sets the server to shutdown with an epitaph. The underlying channel is
236    /// only closed the next time the stream is polled.
237    // TODO(https://fxbug.dev/42161447): Fix behavior or above docs.
238    fn shutdown_with_epitaph(&self, status: zx_status::Status);
239
240    /// Returns true if the server has received the `PEER_CLOSED` signal.
241    fn is_closed(&self) -> bool;
242
243    /// Returns a future that completes when the server receives the
244    /// `PEER_CLOSED` signal.
245    fn on_closed(&self) -> OnSignalsRef<'_>;
246
247    /// Sets and clears the signals provided on peer handle.
248    #[cfg(target_os = "fuchsia")]
249    fn signal_peer(
250        &self,
251        clear_mask: zx::Signals,
252        set_mask: zx::Signals,
253    ) -> Result<(), zx_status::Status>;
254}
255
256/// A type associated with a particular two-way FIDL method, used by servers to
257/// send a response to the client.
258pub trait Responder {
259    /// The control handle for this protocol.
260    type ControlHandle: ControlHandle;
261
262    /// Returns the `ControlHandle` for this protocol.
263    fn control_handle(&self) -> &Self::ControlHandle;
264
265    /// Drops the responder without setting the channel to shutdown.
266    ///
267    /// This method shouldn't normally be used. Instead, send a response to
268    /// prevent the channel from shutting down.
269    fn drop_without_shutdown(self);
270}
271
272/// A marker for a particular FIDL service.
273#[cfg(target_os = "fuchsia")]
274pub trait ServiceMarker: Clone + Sized + Send + Sync + 'static {
275    /// The type of the proxy object upon which calls are made to a remote FIDL service.
276    type Proxy: ServiceProxy<Service = Self>;
277
278    /// The request type for this particular FIDL service.
279    type Request: ServiceRequest<Service = Self>;
280
281    /// The name of the service. Used for service lookup and discovery.
282    const SERVICE_NAME: &'static str;
283}
284
285/// A request to initiate a connection to a FIDL service.
286#[cfg(target_os = "fuchsia")]
287pub trait ServiceRequest: Sized + Send + Sync {
288    /// The FIDL service for which this request is destined.
289    type Service: ServiceMarker<Request = Self>;
290
291    /// Dispatches a connection attempt to this FIDL service's member protocol
292    /// identified by `name`, producing an instance of this trait.
293    fn dispatch(name: &str, channel: AsyncChannel) -> Self;
294
295    /// Returns an array of the service members' names.
296    fn member_names() -> &'static [&'static str];
297}
298
299/// Proxy by which a client sends messages to a FIDL service.
300#[cfg(target_os = "fuchsia")]
301pub trait ServiceProxy: Sized {
302    /// The FIDL service this proxy represents.
303    type Service: ServiceMarker<Proxy = Self>;
304
305    /// Create a proxy from a MemberOpener implementation.
306    #[doc(hidden)]
307    fn from_member_opener(opener: Box<dyn MemberOpener>) -> Self;
308}
309
310/// Used to create an indirection between the fuchsia.io.Directory protocol
311/// and this library, which cannot depend on fuchsia.io.
312#[doc(hidden)]
313#[cfg(target_os = "fuchsia")]
314pub trait MemberOpener: Send + Sync {
315    /// Opens a member protocol of a FIDL service by name, serving that protocol
316    /// on the given channel.
317    fn open_member(&self, member: &str, server_end: Channel) -> Result<(), Error>;
318
319    /// Returns the name of the instance that was opened.
320    fn instance_name(&self) -> &str;
321}
322
323/// The `Client` end of a FIDL connection.
324#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
325pub struct ClientEnd<T> {
326    inner: Channel,
327    phantom: PhantomData<T>,
328}
329
330impl<T> ClientEnd<T> {
331    /// Create a new client from the provided channel.
332    pub fn new(inner: Channel) -> Self {
333        ClientEnd { inner, phantom: PhantomData }
334    }
335
336    /// Get a reference to the underlying channel
337    pub fn channel(&self) -> &Channel {
338        &self.inner
339    }
340
341    /// Extract the underlying channel.
342    pub fn into_channel(self) -> Channel {
343        self.inner
344    }
345}
346
347impl<T: ProtocolMarker> ClientEnd<T> {
348    /// Convert the `ClientEnd` into a `Proxy` through which FIDL calls may be made.
349    ///
350    /// # Panics
351    ///
352    /// If called outside the context of an active async executor.
353    pub fn into_proxy(self) -> T::Proxy {
354        T::Proxy::from_channel(AsyncChannel::from_channel(self.inner))
355    }
356
357    /// Convert the `ClientEnd` into a `SynchronousProxy` through which thread-blocking FIDL calls
358    /// may be made.
359    #[cfg(target_os = "fuchsia")]
360    pub fn into_sync_proxy(self) -> T::SynchronousProxy {
361        T::SynchronousProxy::from_channel(self.inner)
362    }
363}
364
365impl<T> AsHandleRef for ClientEnd<T> {
366    fn as_handle_ref(&self) -> HandleRef<'_> {
367        self.inner.as_handle_ref()
368    }
369}
370
371impl<T> From<ClientEnd<T>> for NullableHandle {
372    fn from(client: ClientEnd<T>) -> NullableHandle {
373        client.into_channel().into()
374    }
375}
376
377impl<T> From<ClientEnd<T>> for Channel {
378    fn from(client: ClientEnd<T>) -> Channel {
379        client.into_channel()
380    }
381}
382
383impl<T> From<NullableHandle> for ClientEnd<T> {
384    fn from(handle: NullableHandle) -> Self {
385        ClientEnd { inner: handle.into(), phantom: PhantomData }
386    }
387}
388
389impl<T> From<Channel> for ClientEnd<T> {
390    fn from(chan: Channel) -> Self {
391        ClientEnd { inner: chan, phantom: PhantomData }
392    }
393}
394
395impl<T: ProtocolMarker> ::std::fmt::Debug for ClientEnd<T> {
396    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
397        write!(f, "ClientEnd(name={}, channel={:?})", T::DEBUG_NAME, self.inner)
398    }
399}
400
401impl<T> HandleBased for ClientEnd<T> {}
402
403/// Trait implemented by types that can be converted from a client.
404pub trait FromClient {
405    /// The protocol.
406    type Protocol: ProtocolMarker;
407
408    /// Converts from a client.
409    fn from_client(value: ClientEnd<Self::Protocol>) -> Self;
410}
411
412impl<T: ProtocolMarker> FromClient for ClientEnd<T> {
413    type Protocol = T;
414
415    fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
416        value
417    }
418}
419
420// NOTE: We can only have one blanket implementation. Synchronous proxies have an implementation
421// that is generated by the compiler.
422impl<T: Proxy> FromClient for T {
423    type Protocol = T::Protocol;
424
425    fn from_client(value: ClientEnd<Self::Protocol>) -> Self {
426        Self::from_channel(AsyncChannel::from_channel(value.into_channel()))
427    }
428}
429
430/// The `Server` end of a FIDL connection.
431#[derive(Eq, PartialEq, Ord, PartialOrd, Hash)]
432pub struct ServerEnd<T> {
433    inner: Channel,
434    phantom: PhantomData<T>,
435}
436
437impl<T> ServerEnd<T> {
438    /// Create a new `ServerEnd` from the provided channel.
439    pub fn new(inner: Channel) -> ServerEnd<T> {
440        ServerEnd { inner, phantom: PhantomData }
441    }
442
443    /// Get a reference to the underlying channel
444    pub fn channel(&self) -> &Channel {
445        &self.inner
446    }
447
448    /// Extract the inner channel.
449    pub fn into_channel(self) -> Channel {
450        self.inner
451    }
452
453    /// Create a stream of requests off of the channel.
454    ///
455    /// # Panics
456    ///
457    /// If called outside the context of an active async executor.
458    pub fn into_stream(self) -> T::RequestStream
459    where
460        T: ProtocolMarker,
461    {
462        T::RequestStream::from_channel(AsyncChannel::from_channel(self.inner))
463    }
464
465    /// Create a stream of requests and an event-sending handle
466    /// from the channel.
467    ///
468    /// # Panics
469    ///
470    /// If called outside the context of an active async executor.
471    pub fn into_stream_and_control_handle(
472        self,
473    ) -> (T::RequestStream, <T::RequestStream as RequestStream>::ControlHandle)
474    where
475        T: ProtocolMarker,
476    {
477        let stream = self.into_stream();
478        let control_handle = stream.control_handle();
479        (stream, control_handle)
480    }
481
482    /// Writes an epitaph into the underlying channel before closing it.
483    pub fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
484        self.inner.close_with_epitaph(status)
485    }
486}
487
488impl<T> AsHandleRef for ServerEnd<T> {
489    fn as_handle_ref(&self) -> HandleRef<'_> {
490        self.inner.as_handle_ref()
491    }
492}
493
494impl<T> From<ServerEnd<T>> for NullableHandle {
495    fn from(server: ServerEnd<T>) -> NullableHandle {
496        server.into_channel().into()
497    }
498}
499
500impl<T> From<ServerEnd<T>> for Channel {
501    fn from(server: ServerEnd<T>) -> Channel {
502        server.into_channel()
503    }
504}
505
506impl<T> From<NullableHandle> for ServerEnd<T> {
507    fn from(handle: NullableHandle) -> Self {
508        ServerEnd { inner: handle.into(), phantom: PhantomData }
509    }
510}
511
512impl<T> From<Channel> for ServerEnd<T> {
513    fn from(chan: Channel) -> Self {
514        ServerEnd { inner: chan, phantom: PhantomData }
515    }
516}
517
518impl<T: ProtocolMarker> ::std::fmt::Debug for ServerEnd<T> {
519    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
520        write!(f, "ServerEnd(name={}, channel={:?})", T::DEBUG_NAME, self.inner)
521    }
522}
523
524impl<T> HandleBased for ServerEnd<T> {}
525
526/// Creates client and server endpoints connected to by a channel.
527pub fn create_endpoints<T: ProtocolMarker>() -> (ClientEnd<T>, ServerEnd<T>) {
528    let (client, server) = Channel::create();
529    let client_end = ClientEnd::<T>::new(client);
530    let server_end = ServerEnd::new(server);
531    (client_end, server_end)
532}
533
534/// Create a client proxy and a server endpoint connected to it by a channel.
535///
536/// Useful for sending channel handles to calls that take arguments
537/// of type `server_end:SomeProtocol`
538///
539/// # Panics
540///
541/// If called outside the context of an active async executor.
542pub fn create_proxy<T: ProtocolMarker>() -> (T::Proxy, ServerEnd<T>) {
543    let (client, server) = create_endpoints();
544    (client.into_proxy(), server)
545}
546
547/// Create a synchronous client proxy and a server endpoint connected to it by a channel.
548///
549/// Useful for sending channel handles to calls that take arguments
550/// of type `server_end:SomeProtocol`
551#[cfg(target_os = "fuchsia")]
552pub fn create_sync_proxy<T: ProtocolMarker>() -> (T::SynchronousProxy, ServerEnd<T>) {
553    let (client, server) = create_endpoints();
554    (client.into_sync_proxy(), server)
555}
556
557/// Create a request stream and a client endpoint connected to it by a channel.
558///
559/// Useful for sending channel handles to calls that take arguments
560/// of type `client_end:SomeProtocol`
561///
562/// # Panics
563///
564/// If called outside the context of an active async executor.
565pub fn create_request_stream<T: ProtocolMarker>() -> (ClientEnd<T>, T::RequestStream) {
566    let (client, server) = create_endpoints();
567    (client, server.into_stream())
568}
569
570/// Create a request stream and proxy connected to one another.
571///
572/// Useful for testing where both the request stream and proxy are
573/// used in the same process.
574///
575/// # Panics
576///
577/// If called outside the context of an active async executor.
578pub fn create_proxy_and_stream<T: ProtocolMarker>() -> (T::Proxy, T::RequestStream) {
579    let (client, server) = create_endpoints::<T>();
580    (client.into_proxy(), server.into_stream())
581}
582
583/// Create a request stream and synchronous proxy connected to one another.
584///
585/// Useful for testing where both the request stream and proxy are
586/// used in the same process.
587///
588/// # Panics
589///
590/// If called outside the context of an active async executor.
591#[cfg(target_os = "fuchsia")]
592pub fn create_sync_proxy_and_stream<T: ProtocolMarker>() -> (T::SynchronousProxy, T::RequestStream)
593{
594    let (client, server) = create_endpoints::<T>();
595    (client.into_sync_proxy(), server.into_stream())
596}
597
598/// The type of a client-initiated method.
599#[derive(Copy, Clone, Debug)]
600pub enum MethodType {
601    /// One-way method, also known as fire-and-forget.
602    OneWay,
603    /// Two-way method.
604    TwoWay,
605}