Skip to main content

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